zoukankan      html  css  js  c++  java
  • 2017 CCPC杭州 题解

    2017CCPC杭州题目PDF

    Problem A. Super-palindrome

    题解:

      给你一个字符串,每一步可以将一个字符替换为另一个字符,问你最少多少步可以使得,该字符串任意奇数子串为回文串,偶数子串为回文串。

    满足上面条件一定是ababab这种形式,所以我们只要找到数量最多的两种字符用n-numa-numb得到ans1,有可能一种字符的数量过多,这时候我们只要把所有字符都变成这种字符就行了。得到n-numa,ans2;

    在ans1和ans2中去最小值就是答案了;

    参考代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int maxn=210;
    int T,a[maxn];
    char s[maxn];
    
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%s",s+1); 
            int len=strlen(s+1),ans=0;
            for(int i=1;i<=len;++i) a[i]=s[i]-'a'+1;
            for(int i=1;i<=26;++i)
            {
                for(int j=1;j<=26;++j)
                {
                    int sum=0;
                    for(int k=1;k<=len;++k)
                    {
                        if((k&1)&&a[k]==i) ++sum;
                        if(!(k&1)&&a[k]==j) ++sum;
                    }
                    ans=max(ans,sum);
                }
            }
            for(int i=1;i<=26;++i)
            {
                int sum=0;
                for(int k=1;k<=len;++k)
                    if(a[k]==i) sum++;
                ans=max(ans,sum);
            }
            printf("%d
    ",len-ans);
            
        }
        
        return 0;
    }
    View Code

    Problem B. Master of Phi

      公式化简;

    参考代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long LL;
    const int mod=998244353;
    int quick_pow(int a,int b){int ans=1;while(b) {if(b&1) ans=1LL*a*ans%mod;a=1LL*a*a%mod;b>>=1;} return ans;}
    int main()
    {
        int t;
        scanf("%d",&t);
        while(t--)
        {
            int m;
            scanf("%d",&m);
            LL ans=1;
            for(int i=1;i<=m;i++)
            {
                int p,q;
                scanf("%d%d",&p,&q);
                ans=1LL*ans*(quick_pow(p,q)+1LL*quick_pow(p,q-1)*(p-1)%mod*q%mod)%mod;
            }
            printf("%lld
    ",ans);
        }
    }
    View Code

    Problem C. Hakase and Nano

    题解:

      给你n对石头,每堆a[i]个,一个d,d==1时表示Hakase先手,d==2时表示Nano先手,每次从一堆中拿任意个石头,至少拿一个;但是这是一个不平等博弈,就是Hakase可以连续拿两次,而Nano只能连续拿一次。问你Hakase是否可以取胜。

      首先如果d==1,那么只有当所有堆石头的数量都为1且数量%3==1的时候Hakase才必败,其他情况都是必胜。

    d==2的时候,因为N想赢所以肯定想转换到上述H会输的状态,所以H在n是3的倍数,且有n-1个数为1时会输(这时N只需从不是1的那堆石子里拿掉一些石子使状态变为1 1 1),或者n是3的倍数余1,且n个数为1时会输(此时N只需拿掉一堆石子,H就到了必输态),或者n是3的倍数余1,且n-1个数为1时会输(此时N只需拿掉一堆不是1的石子,H就到了必输态)。

    参考代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int T,n,d,x;
    
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            int cnt=0;
            scanf("%d%d",&n,&d);
            for(int i=1;i<=n;++i) scanf("%d",&x),cnt+=(x==1);
            if(d==1)
            {
                if(cnt==n&&n%3==0) puts("No");
                else puts("Yes");
            }
            else
            {
                if(n%3==1&&cnt>=n-1) puts("No");
                else if(n%3==0&&cnt==n-1) puts("No");
                else puts("Yes");
            }
        }
        
        return 0;
    }
    View Code

    Problem D. Master of Random

    题解:

      给你一棵树,每个节点有个权值,现在这个树是随机的,现在随即选择一颗子树,问你这棵子树的节点权值和的期望为多少;

      我们考虑对于一颗子树上面的点,他到子树的根必定在他到整个树的根的路径上面,然后,我们考虑每次添加一个节点,他要么是子树根节点,要么自己单独型号才能一个子树。

    参考代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define mod 998244353
    typedef long long ll;
    const int maxn=1e5+10;
    int T,n;
    ll num,sum,ans,a[maxn],f[maxn];
    ll qpow(ll x,ll y)
    {
        ll res=1;
        while(y)
        {
            if(y&1) res=res*x%mod;
            x=x*x%mod;
            y>>=1;
        }
        return res;
    }
    
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d",&n);
            sum=0;ans=0;
            num=qpow(n,mod-2);
            for(int i=1;i<=n;i++) scanf("%lld",a+i);
            for(int i=1;i<=n;i++)
            {
                  f[i]=(sum*qpow(i-1,mod-2)%mod+1)%mod;
                  sum=(sum+f[i])%mod;
                  ans=(ans+a[i]*f[i]%mod)%mod;
            }
            ans=(ans*num)%mod;
            
            printf("%lld
    ",ans);
        }
          return 0;
    }
    View Code

    Problem E. Master of Subgraph

    题解:

      题目给你一个树图,然后每个节点一个权值a[i],给你一个m,对于x=1~m :问你该树图里面是否有连通子图的值为x,输出x对应取值下的答案(0/1);

      我们考虑点分治,用bitset维护经过每个点的链的权值和。

    参考代码:

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int INF=0x3f3f3f3f;
    const int maxn=3e3+10;
    const int maxm=1e5+10;
    bitset<maxm> bit[maxn],ans;
    int T,n,m,w[maxn];
    vector<int> g[maxn];
    int root,mx[maxn],siz[maxn],S;
    bool vis[maxn];
    
    void getroot(int u,int fa)
    {
        siz[u]=1;mx[u]=0;
        for(int i=0,len=g[u].size();i<len;++i)
        {
            int v=g[u][i];
            if(v==fa || vis[v]) continue;
            getroot(v,u);
            siz[u]+=siz[v];
            mx[u]=max(mx[u],siz[v]);
        }
        mx[u]=max(mx[u],S-mx[u]);
        if(mx[u]<mx[root]) root=u;
    
    }
    
    void calc(int u,int fa)
    {
        siz[u]=1;bit[u]<<=w[u];
        for(int i=0,len=g[u].size();i<len;++i)
        {
            int v=g[u][i];
            if(vis[v]||v==fa) continue;
            bit[v]=bit[u];
            calc(v,u);
            bit[u]|=bit[v];
            siz[u]+=siz[v];
        }
    }
    
    void solve(int u)
    {
        vis[u]=true;
        bit[u].reset();bit[u].set(0);
        calc(u,0);
        ans|=bit[u];
        for(int i=0,len=g[u].size();i<len;++i)
        {
            int v=g[u][i];
            if(vis[v]) continue;
            root=0; S=siz[v];
            getroot(v,0);
            solve(root);
        }
    
    }
    
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            ans.reset();
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;++i) g[i].clear(),vis[i]=0;
            for(int i=1;i<n;++i)
            {
                int u,v;
                scanf("%d%d",&u,&v);
                g[u].push_back(v);
                g[v].push_back(u);
            }
            for(int i=1;i<=n;++i) scanf("%d",w+i);
            S=n; root=0;mx[0]=INF;
            getroot(1,0);
            solve(1);
            for(int i=1;i<=m;++i) 
                printf("%d",(int)ans[i]);
            puts("");
            
                 
        }
    
        return 0;
    }
    View Code

    Problem J. Master of GCD

    题意:

      给出T组数据(1 <= T  <= 10),每组数据中,有两个数n(1  <= n <= 10^5)和 m (1 <= m <= 10^5)。其中 n 表示有n个由1组成的数, m表示下面给出m组数据,每组数据由 p,q,k 组成。表示区间p 到 q,增大k倍(k 等于2 或者 3).输出这n个数最终的最大公约数。由于数据比较大,因此需要mod 998244353。 
      差分一下,维护2的次幂和3的次幂;

    参考代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define mod 998244353
    typedef long long ll;
    const int maxn=1e5+10;
    int T,n,m;
    ll x[maxn],y[maxn];
    ll qpow(ll x,ll y)
    {
        ll res=1;
        while(y)
        {
            if(y&1) res=res*x%mod;
            x=x*x%mod;
            y>>=1;
        }
        return res;
    }
    
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            scanf("%d%d",&n,&m);
            for(int i=0;i<=n;++i) x[i]=y[i]=0;
            for(int i=1;i<=m;++i)
            {
                int l,r,xx;
                scanf("%d%d%d",&l,&r,&xx);
                if(xx==2) x[l]++,x[r+1]--;
                else y[l]++,y[r+1]--;
            }
            
            for(int i=2;i<=n;++i) x[i]+=x[i-1],y[i]+=y[i-1];
            ll ans1=x[1],ans2=y[1];
            for(int i=2;i<=n;++i)
                ans1=min(ans1,x[i]),ans2=min(ans2,y[i]);
            ll ans=qpow(2,ans1)*qpow(3,ans2)%mod;
            printf("%lld
    ",ans);
        }
        
        return 0;
    }
    View Code

    Problem K. Master of Sequence

    题解:

     参考代码:

    #include<bits/stdc++.h>
    #define mod 998244353
    const int maxn=1e6+10;
    using namespace std;
    typedef long long ll;
    struct node{
        ll a,b;
    } p[maxn];
    int T,n,m,num[1010][1010],cnt[1010];
    ll s;
    int main()
    {
        scanf("%d",&T);
        while(T--)
        {
            s=0;
            memset(num,0,sizeof num);
            memset(cnt,0,sizeof cnt);
            scanf("%d%d",&n,&m);
            for(int i=1;i<=n;++i) scanf("%d",&p[i].a);
            for(int i=1;i<=n;++i)
            {
                scanf("%d",&p[i].b);
                s+=(p[i].b/p[i].a);
                cnt[p[i].a]++;
                num[p[i].a][p[i].b%p[i].a]++;
            }
            for(int i=1;i<=1000;i++)
                for(int j=i-1;j>=0;j--)
                    num[i][j]+=num[i][j+1];
            
            while(m--)
            {
                int ty,y,z;
                scanf("%d",&ty);
                if(ty==1)
                {
                    scanf("%d%d",&y,&z);
                    for(int i=p[y].b%p[y].a;i>=1;--i) num[p[y].a][i]--;
                    s-=(p[y].b/p[y].a);
                    cnt[p[y].a]--;
                    p[y].a=z;
                    s+=(p[y].b/p[y].a);
                    cnt[z]++;
                    for(int i=p[y].b%z;i>=1;--i) num[z][i]++;
                }
                else if(ty==2)
                {
                    scanf("%d%d",&y,&z);
                    for(int i=p[y].b%p[y].a;i>=1;--i) num[p[y].a][i]--;
                    s-=(p[y].b/p[y].a);
                    p[y].b=z;
                    s+=(p[y].b/p[y].a);
                    for(int i=p[y].b%p[y].a;i>=1;--i) num[p[y].a][i]++;
                }
                else
                {
                    ll k;
                    scanf("%lld",&k);
                    ll l=1,r=1e13,ans;
                    while(l<=r)
                    {
                        ll mid=l+r>>1;
                        ll sum=-s;
                        for(int i=1;i<=1000;++i) sum+=mid/i*cnt[i]-num[i][mid%i+1];
                        if(sum>=k) r=mid-1,ans=mid;
                        else l=mid+1;
                    }
                    printf("%lld
    ",ans);
                }
            }
        }
        
        return 0;
    }
    View Code

     

  • 相关阅读:
    hdu 1290 献给杭电五十周年校庆的礼物 (DP)
    hdu 3123 GCC (数学)
    hdu 1207 汉诺塔II (DP)
    hdu 1267 下沙的沙子有几粒? (DP)
    hdu 1249 三角形 (DP)
    hdu 2132 An easy problem (递推)
    hdu 2139 Calculate the formula (递推)
    hdu 1284 钱币兑换问题 (DP)
    hdu 4151 The Special Number (DP)
    hdu 1143 Tri Tiling (DP)
  • 原文地址:https://www.cnblogs.com/csushl/p/11764086.html
Copyright © 2011-2022 走看看