CodeForces 900D-Unusual Sequences(快速幂,莫比乌斯反演)

CodeForces 900D-Unusual Sequences

题目原址

[http://codeforces.com/problemset/problem/900/D]

题意

有这样的序列 a 1 , a 2 , a 3 ⋅ ⋅ ⋅ a n a_{1},a_{2},a_{3}···a_{n} a1,a2,a3an 使得他们的和为 y y y ,最大公因数为 x x x,问满足这样的序列有多少个。

题解

练习题里的题,我原来根本看不出是莫比乌斯反演。
显然对于每个 a i a_{i} ai 都是 x x x 的倍数,于是 y y y x x x 的倍数。
如果不考虑最大公因数是 x x x 这个条件的话,把每个 a i a_{i} ai 都除以 x x x,就是纯粹的有序整数拆分问题,也就是 2 y x − 1 2^{\frac{y}{x}-1} 2xy1
但这显然是 ∑ d ∣ y x [ gcd ⁡ = d ] \sum_{d|\frac{y}{x}}[\gcd=d] dxy[gcd=d] 的情况数,所以我们要去掉 ∑ [ gcd ⁡ ≠ 1 ] \sum[\gcd\neq 1] [gcd̸=1] 的情况,也就是 ∑ d ∣ y x [ gcd ⁡ = d & & d ! = 1 ] \sum_{d|\frac{y}{x}}[\gcd=d \&\& d!=1] dxy[gcd=d&&d!=1] 的情况。
上面是一种思路,另一种思路就是莫比乌斯反演了,如果我们用 f ( n ) f(n) f(n) 表示 ∑ n ∣ y x [ gcd ⁡ = n ] \sum_{n|\frac{y}{x}}[\gcd=n] nxy[gcd=n]
那么我们就是要求 f ( 1 ) f(1) f(1),然后他的倍数和 F ( n ) = ∑ n ∣ d f ( d ) F(n)=\sum_{n|d}f(d) F(n)=ndf(d) 就表示 ∑ n ∣ y x [ n ∣ gcd ⁡ ] \sum_{n|\frac{y}{x}}[n|\gcd] nxy[ngcd] 的情况数了,也就是 2 y x n − 1 2^{\frac{\frac{y}{x}}{n}-1} 2nxy1 种情况,所以我们也直接枚举莫比乌斯函数值不为0的约数就可以了。

代码

#include
using namespace std;
typedef long long ll;
const int maxn=1e6+7;
const int mod=1e9+7;
int yue[maxn],numy,n;
ll ans;
ll power(ll a,ll b){
    ll ans=1;
    while(b){
        if(b&1)ans=(ans*a)%mod;
        a=(a*a)%mod;
        b>>=1;
    }
    return ans;
}
void dfs(int len,int mu,ll s){
    if(len>numy){
        ans=((ans+(ll)mu*power(2,n/s-1))%mod+mod)%mod;
        return;
    }
    dfs(len+1,mu,s);
    dfs(len+1,-mu,s*yue[len]);
}
int main(){
    #ifdef LOCAL
    freopen("in.txt","r",stdin);
    freopen("out.txt","w",stdout);
    #endif // LOCAL
    ios::sync_with_stdio(false);
    int x,y;
    while(cin>>x>>y){
        if(y%x){
            cout<<0<<endl;
            continue;
        }
        numy=0;ans=0;
        n=y/x;int tmp=n;
        for(int i=2;i<=n;i++)
            if(n%i==0){
                yue[++numy]=i;
                while(n%i==0)
                    n/=i;
            }
        n=tmp;
        dfs(1,1,1);
        cout<<ans<<endl;
    }
}

你可能感兴趣的:(题库)