zoukankan      html  css  js  c++  java
  • AtCoder Regular Contest 106 部分题解 A-D

    AtCoder Regular Contest 106

    A:给一个N,找出一对数字使得3x+5y=N。或者说明无解。

    题解:直接枚举x,看N-3^x是不是5的幂次就好了。

    #include<bits/stdc++.h>
    
    using namespace std;
    
    map<long long, int>H;
    
    int main(){
        long long x;
        cin>>x;
    
        int idx=1;
        long long t=5;
        while(t<=x){
            H[t]=idx++;
            t*=5;
        }
    
        long long a=1, b=-1;
        t=3;
        for(;t<x;t*=3){
            if(H.count(x-t)){
                b=H[x-t];
                break;
            }
            ++a;
        }
    
        if(b!=-1){
            cout<<a<<" "<<b;
        }else{
            cout<<"-1";
        }
    
        return 0;
    }
    

    B:给你一个无向图,每个点有点权。每次能把一条边连接的两个节点的点权一个加一,一个减一。问你能不能通过一系列操作使得每一个点权到达预设的值。

    题解:检查每一个连通块的总权值和是不是一样,一样的话,我们总是能通过某种方式使得它变化成预设的值。例如通过类似于从叶子开始变化的方式,达到预设值之后就剪去叶子,再开始新的叶子,显然这种方式是可行的。

    #include<bits/stdc++.h>
    
    using namespace std;
    
    const int N = 200005;
    
    typedef long long LL;
    
    int a[N], b[N];
    
    int n, m;
    
    int f[N], st[N], top;
    
    LL sum[N][2];
    
    inline int Find(int x){
        return x==f[x]?x:f[x]=Find(f[x]);
    }
    
    int main(){
        cin>>n>>m;
        for(int i=1;i<=n;++i)f[i]=i;
    
        for(int i=1;i<=n;++i){
            cin>>a[i];
        }
    
        for(int i=1;i<=n;++i){
            cin>>b[i];
        }
    
        for(int i=1;i<=m;++i){
            int u, v;
            cin>>u>>v;
            int fu=Find(u);
            int fv=Find(v);
    
            if(fu==fv){
                continue;
            }else{
                f[fv]=fu;
            }
        }
    
        for(int i=1;i<=n;++i){
            st[++top]=Find(i);
        }
    
        sort(st+1,st+top+1);
        top=unique(st+1,st+top+1)-st-1;
    
        for(int i=1;i<=n;++i){
            int fa=lower_bound(st+1,st+1+top,Find(i))-st;
            sum[fa][0]+=a[i];
            sum[fa][1]+=b[i];
        }
    
        int flag=1;
        for(int i=1;i<=top;++i){
            if(sum[i][0]!=sum[i][1]){
                flag=0;
                break;
            }
        }
    
        if(flag==1){
            cout<<"Yes";
        }else{
            cout<<"No";
        }
    
        return 0;
    }
    

    C:现在A,B各自给定一个计数算法,现在需要你构造一种方案使得他们的结果相差M。

    A:n个区间,按照左端点排序。从左端点最小的开始,如果当前的区间与之前所有所选的区间没有交,那么选上这个区间。

    B:n个区间,按照右端点排序。从右端点最小的开始,如果当前的区间与之前所有所选的区间没有交,那么选上这个区间。

    题解:首先,B算法是正确的。这是一个经典的选取最多无交点区间数的贪心算法,所以M<0直接白给。M等于0的时候,我们需要构造类似于123123的这种区间。首先可以证明,m>n-2是无解的。m=n,m=n-1会简单的推出矛盾。现在给出一种m=n-2的构造方案。1334455...212。如果需要减少,那就在区间内334455...的地方进行嵌套,然后注意特判就能过。

    #include<bits/stdc++.h>
    
    using namespace std;
    
    int n, m;
    
    int main(){
        cin>>n>>m;
    
        if(n==1){
            if(m==0){
                cout<<"1 2"<<endl;
            }else{
                cout<<"-1"<<endl;
            }
            return 0;
        }
    
        if(m<0||m>n-2){
            cout<<"-1"<<endl;
            return 0;
        }
    
        if(m==0){
            for(int i=1;i<=n;++i){
                cout<<i<<" "<<i+n<<endl;
            }
        }else{
            cout<<"1 "<<2*n-1<<endl;
            cout<<2*n-2<<" "<<2*n<<endl;
    
            for(int i=0;i<m-1;++i){
                cout<<2*i+2<<" "<<2*i+3<<endl;
            }
    
            for(int i=0;i<n-m-1;++i){
                cout<<i+2*m<<" "<<i+(n+m-1)<<endl;
            }
        }
    
        return 0;
    }
    

    D:对于X=1...K。求下列算式的值。

    [sum_{i=1}^nsum_{j=i+1}^{n}(A_iA_j)^X ]

    题解:推式子:

    [sum_{i=1}^nsum_{j=i+1}^{n}(A_iA_j)^X=frac{1}{2}(sum_{i=1}^{n}sum_{j=1}^{n}(A_i+A_j)^X-sum_{i=1}^{n}(2*A_i)^X) ]

    其实对于中间的X次幂,可以用二项式进行展开。

    [sum_{i}sum_{j}(A_i+A_j)^X=sum_isum_jsum_{k=0}^{X}C_{X}^{k}A_i^XA_j^X ]

    更换枚举顺序:

    [sum_isum_jsum_{k=0}^{X}C_{X}^{k}A_i^XA_j^X=sum_{k=0}^{X}C_{X}^{k}sum_iA_i^Xsum_jA_j^X ]

    然后就无了。

    #include <bits/stdc++.h>
    
    using namespace std;
    
    const int MOD = 998244353;
    
    const int N = 200005;
    
    int n, k;
    
    int a[N], t[N], t1[N];
    
    int f[305], f1[305];
    
    int C[305][305];
    
    void add(int& x, int y){
        x+=y;
        if(x>MOD)x-=MOD;
    }
    
    void sub(int& x, int y){
        x-=y;
        if(x<0)x+=MOD;
    }
    
    void mult(int& x, int y){
        x=1ll*x*y%MOD;
    }
    
    int inv2;
    
    int powmod(int x, int y){
        int res=1;
        while(y){
            if(y&1)mult(res,x);
            y>>=1;
            mult(x,x);
        }
        return res;
    }
    
    int main(){
        cin>>n>>k;
        for(int i=1;i<=n;++i)cin>>a[i];
    
        f[0]=n;
        for(int i=1;i<=n;++i)t[i]=1,t1[i]=1;
        for(int i=1;i<=k;++i){
            for(int j=1;j<=n;++j){
                mult(t[j],a[j]);
                mult(t1[j],2*a[j]);
            }
            for(int j=1;j<=n;++j){
                add(f[i],t[j]);
                add(f1[i],t1[j]);
            }
        }
    
        for(int i=0;i<=300;++i){
            C[i][0]=C[i][i]=1;
        }
        for(int i=1;i<=300;++i){
            for(int j=1;j<i;++j){
                add(C[i][j],C[i-1][j-1]+C[i-1][j]);
            }
        }
    
        inv2=powmod(2,MOD-2);
    
        for(int x=1;x<=k;++x){
            int ans=0;
            for(int d=0;d<=x;++d){
                int t=1ll*f[d]*f[x-d]%MOD*C[x][d]%MOD;
                add(ans,t);
            }
            sub(ans,f1[x]%MOD);
            mult(ans,inv2);
            cout<<ans<<endl;
        }
    
        return 0;
    }
    
    
  • 相关阅读:
    Java设计模式の工厂模式
    写Java代码分别使堆溢出,栈溢出
    Java7/8 中的 HashMap 和 ConcurrentHashMap 全解析
    Java集合---ConcurrentHashMap原理分析
    Java 集合类详解
    HashMap详谈以及实现原理
    Java设计模式の代理模式
    Java设计模式の单例模式
    mysql之 navicat表权限设置
    MySQL之You can't specify target table for update in FROM clause解决办法
  • 原文地址:https://www.cnblogs.com/JohnRan/p/13879230.html
Copyright © 2011-2022 走看看