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}^n\sum_{j=i+1}^{n}(A_iA_j)^X \]

题解:推式子:

\[\sum_{i=1}^n\sum_{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_i\sum_j\sum_{k=0}^{X}C_{X}^{k}A_i^XA_j^X \]

更换枚举顺序:

\[\sum_i\sum_j\sum_{k=0}^{X}C_{X}^{k}A_i^XA_j^X=\sum_{k=0}^{X}C_{X}^{k}\sum_iA_i^X\sum_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;
}

posted @ 2020-10-26 16:38  John_Ran  阅读(117)  评论(0编辑  收藏  举报