Codeforces Round #359 (Div. 1)

来源:互联网 发布:java 文件存在判断 编辑:程序博客网 时间:2024/06/09 18:24

A. Robbers’ watch

  由于两个数位数加起来不能超过7,枚举可能出现的数,暴力统计,有一些小坑要细心。

#include <bits/stdc++.h>using namespace std;#define ll long longll change(ll x){    ll res = 0;    ll bit = 1;    while(x){        res += (x%7)*bit;        x /= 7;        bit *= 10;    }    return res;}int fa[] = {1,1,2,6,24,120,720,5040,40320};int C(int n,int k){    return fa[n]/fa[k]/fa[n-k];}ll len(int x){    int res = 0;    while(x){        x /= 10;        res++;    }    return max(res,1);}bool check(int x,int len){    bool vis[11];    for(int i=0;i<7;i++){        vis[i] = 0;    }    while(len--){        if(x%10 > 6){            return 0;        }        int cur = x%10;        if(vis[cur]){            return 0;        }        vis[cur] = 1;        x /= 10;    }    return 1;}int num_n[5555];int num_m[5555];int cntn = 0;int cntm = 0;int lenn;int lenm;bool judge(int x,int lenx,int y,int leny){    bool vis[11];    for(int i=0;i<7;i++){        vis[i] = 0;    }    while(lenx--){        int cur = x%10;        if(vis[cur]){            return 0;        }        vis[cur] = 1;        x /= 10;    }    while(leny--){        int cur = y%10;        if(vis[cur]){            return 0;        }        vis[cur] = 1;        y /= 10;    }    return 1;}int main(){    ll n,m;    cin>>n>>m;    if(n==1 && m==1){        cout<<0<<endl;        return 0;    }    n--;    m--;    ll nn = change(n);    ll mm = change(m);    lenn = len(nn);    lenm = len(mm);    if(lenn + lenm >7){        cout<<0<<endl;        return 0;    }    for(int i=0;i<=nn;i++){        if(check(i,lenn)){            num_n[cntn++] = i;        }    }    for(int i=0;i<=mm;i++){        if(check(i,lenm)){            num_m[cntm++] = i;        }    }    int ans = 0;    for(int i=0;i<cntn;i++){        for(int j=0;j<cntm;j++){            int ii = num_n[i];            int jj = num_m[j];            if(judge(ii,lenn,jj,lenm)){                ans++;            }        }    }    cout<<ans<<endl;    return 0;}

B. Kay and Snowflake

  参考倍增法求LCA,找出每个节点size最大的儿子作为大儿子,倍增儿子寻找答案。即往最大的后代方向找,直到找到第一个最大后代不会过大为止。

#include <bits/stdc++.h>using namespace std;#define ll long longconst int maxn = 300010;vector<int> G[maxn];int maxSon[maxn];int size[maxn];void dfs(int u){    int sz = G[u].size();    size[u] = 1;    for(int i=0;i<sz;i++){        int v = G[u][i];        dfs(v);        size[u] += size[v];        maxSon[u] = max(maxSon[u],size[v]);    }}int n,q;int bestSon[maxn][22];int main(){    cin>>n>>q;    for(int i=2;i<=n;i++){        int pp;        scanf("%d",&pp);        G[pp].push_back(i);    }    dfs(1);    for(int i=1;i<=n;i++){        int sz = G[i].size();        for(int j=0;j<sz;j++){            int v = G[i][j];            if(size[v]>size[bestSon[i][0]]){                bestSon[i][0] = v;            }        }    }    for(int i=1;i<=20;i++){        for(int j=1;j<=n;j++){            bestSon[j][i] = bestSon[ bestSon[j][i-1] ][i-1] ;        }    }    while(q--){        int u;        scanf("%d",&u);        if(maxSon[u]*2<=size[u]){            printf("%d\n",u);            continue;        }        int ans = u;        for(int i=0;i<20;i++){            int v = bestSon[ans][i];            if(maxSon[v]*2<=size[u]){                if(i==0){                    ans = v;                    break;                }                ans = bestSon[ans][i-1];                i = -1;                continue;            }        }        printf("%d\n",ans);    }    return 0;}
0 0