T1 String

题意

给定一个字符串 ,求 中不同字符的个数。()

分析

扫一遍 ,开个桶记录一下哪些字母用过,如果没用过,标记它用过,并将答案

代码如下

#include <bits/stdc++.h>
#define LL long long
#define N 1000005
using namespace std;
int v[N], ans;
LL z = 1;
char s[N];
int main(){
    int i, j, n, m;
    scanf("%s", s + 1);
    n = strlen(s + 1);
    for(i = 1; i <= n; i++){
        if(!v[s[i]]) v[s[i]] = 1, ans++;
    }
    printf("%d", ans);
    return 0;
}

T2 Number

题意

如果一个数字 ,存在一个 ,使得这个数是每一位的 次方之和,则这个数是好数字。给出 个数,问有多少个数字是好数字。()

分析

对于一个数字,我们最多只用枚举 )。
然后我们枚举 判断即可。

代码如下

#include <bits/stdc++.h>
#define LL long long
using namespace std;
LL z = 1;
int a[15], cnt;
int ksm(int a, int b){
    if(a == 0) return 0;
    if(a == 1) return 1;
    int s = 1;
    while(b){
        if(b & 1) s = s * a;
        a = a * a;
        b >>= 1;
    }
    return s;
}
int pd(int x){
    int i, j, k, maxn = 0, v = x, sum;
    cnt = 0;
    while(x){
        a[++cnt] = x % 10;
        maxn = max(maxn, x % 10);
        x /= 10;
    }
    for(i = 0; i <= 20; i++){
        if(ksm(maxn, i) > v) break;
        sum = 0;
        for(j = 1; j <= cnt; j++){
            sum += ksm(a[j], i);
        }
        if(sum == v) return 1;
    }
    return 0;
}
int main(){
    int i, j, n, m, ans = 0;
    scanf("%d", &n);
    for(i = 1; i <= n; i++){
        scanf("%d", &j);
        ans += pd(j);
    }
    printf("%d", ans);
    return 0;
}

T3 Tree

题意

给定一棵树,决定一个根节点,使得 最小,求最小值。

分析

树形dp。
先以 为根节点求出每一个点深度,和每一个点的子树大小。
表示以 为根节点所有点的深度和。
考虑 和其儿子节点 之间的转移。
为根会使 的子树中所有点的深度 ,会使不在 子树的点深度
于是转移方程:

代码如下

#include <bits/stdc++.h>
#define LL long long
#define N 1000005
using namespace std;
LL z = 1;
struct node{
    int a, b, n;
}d[N * 2];
int h[N], fa[N], siz[N], dep[N], cnt, n;
LL w[N], ans[N], qaq = 1e18;
void cr(int a, int b){
    d[++cnt].a = a; d[cnt].b = b; d[cnt].n = h[a]; h[a] = cnt;
}
void dfs(int a){
    int i, b;
    siz[a] = 1;
    w[a] = dep[a];
    for(i = h[a]; i; i = d[i].n){
        b = d[i].b;
        if(b == fa[a]) continue;
        fa[b] = a;
        dep[b] = dep[a] + 1;
        dfs(b);
        w[a] += w[b];
        siz[a] += siz[b];
    }
}
void dfs1(int a){
    int i, b;
    for(i = h[a]; i; i = d[i].n){
        b = d[i].b;
        if(b == fa[a]) continue;
        ans[b] = ans[a] + z * n - z * 2 * siz[b];
        dfs1(b);
    }
}
int main(){
    int i, j, m, a, b;
    scanf("%d", &n);
    for(i = 1; i < n; i++){
        scanf("%d%d", &a, &b);
        cr(a, b);
        cr(b, a);
    }
    dfs(1);
    ans[1] = w[1];
    dfs1(1);
    //for(i = 1; i <= n; i++) printf("%lld\n", ans[i]);
    for(i = 1; i <= n; i++) qaq = min(qaq, ans[i]);
    printf("%lld", qaq);
    return 0;
}

T4 Talk

题意

牛可乐 要讲 件事情,我们把这些事情从 标号。
牛可乐每讲一件事需要耗费一个单位的时间,但是 牛可乐讲事情和普通人不同:牛可乐在 讲完 第 件事时,只有 的概率继续讲下一件事(第 件),也就是说,牛可乐讲完第 件事后有 的概率从第 件事开始讲!
当 牛可乐讲完第 件事,并且决定讲下一件事时,牛可乐才算是把这 件事讲完了。
牛妹是个不耐烦的女孩子,她想问问你 牛可乐期望要讲多久才能把 件事情全部讲完。

分析

表示第一次讲到 的时间。那么最终答案为
那么 可以从 成功讲一件事转移来,也可以从 失败讲一件事回到 ,再讲到 得来。
那么转移方程:
其中 为从 讲到 需要的时间。

代码如下

#include <bits/stdc++.h>
#define N 100005
using namespace std;
double f[N], p;
int main(){
    int i, j, n, m;
    scanf("%d", &n);
    for(i = 2; i <= n + 1; i++){
        scanf("%lf", &p);
        f[i] = (p * (f[i - 1] + 1) + (1 - p) * (f[i - 1] + 1 - f[i - 2])) / p;
    }
    printf("%.3lf", f[n + 1]);
    return 0;
}