Codeforces Round #450 (Div. 2)D. Unusual Sequences【組合數學】【容斥】

題目鏈接:https://codeforc.es/contest/900/problem/D

題目大意:要你構造一個長度爲nn(未知)的數組,使得ai>=1a_i>=1gcd(a1,a2,,an)=xgcd(a_1,a_2,\dots,a_n)=xi=1nai=y\sum_{i=1}^na_i=y,輸出種類數。

思路:從gcd(a1,a2,,an)=xgcd(a_1,a_2,\dots,a_n)=xi=1nai=y\sum_{i=1}^na_i=y我們可以推斷出對於構造的aa數組,每個數都是xx的倍數,且所有數的和爲yy,由此可以聯想到類似於隔板法:將yx\frac{y}{x}份至少分成兩份,最多分成yx\frac{y}{x}份,不能爲空

這樣總的分類數即爲:令cntcnt爲份數,i=2cnt1Ccnt1i=2cnt11\sum_{i=2}^{cnt-1}C_{cnt-1}^{i}=2^{cnt-1}-1

但是我們注意到單純這樣分是存在問題的,例如:x=2,y=8x=2,y=8,我們可能會分出{4,4}\{4,4\}這樣錯誤的情況,所以我們需要去除掉不合法的種類數,我們可以發現:不合法的種類數產生的原因爲:份數cntcntyx\frac{y}{x}的因子,所以我們減掉份數cntcntyx\frac{y}{x}的因子的值就okok了。

AC代碼:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
ll qpow(ll x,ll y){
    ll ans=1;
    while(y){
        if(y&1){
            ans=ans*x%mod;
        }
        x=x*x%mod;
        y>>=1;
    }
    return ans;
}
map<ll ,ll >mp;
ll dfs(ll x){
    if(mp[x]){
        return mp[x];//用map映射直接返回,減少多餘計算
    }
    if(x==1){
        return 1;
    }
    mp[x]=(qpow(2,x-1)-1+mod)%mod;
    for(ll i=2;i*i<=x;i++){
        if(x%i==0){
            mp[x]=(mp[x]-dfs(x/i)+mod)%mod;
            if(i*i!=x){
                mp[x]=(mp[x]-dfs(i)+mod)%mod;
            }
        }
    }
    return mp[x];
}
int main()
{
    ll x,y;
    cin>>x>>y;
    if(y%x!=0){//序列總和不是gcd的倍數
        cout<<0<<endl;
    }
    else{
        ll cnt=y/x;
        ll ans=dfs(cnt);
        cout<<ans<<endl;
    }
    return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章