1. 程式人生 > 實用技巧 >AtCoder Regular Contest 106 部分題解 A-D

AtCoder Regular Contest 106 部分題解 A-D

AtCoder Regular Contest 106

A:給一個N,找出一對數字使得3^x+5^y=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;
}