Sum of gcd of Tuples【容斥定理】

题意:

  考虑长度为 (N) 且由 (1)(K) 之间的整数组成的序列 ({A_1,...,A_N})(包括 (K))。有 (K^N) 个这样的序列,求出 (gcd(A_1,...,A_N)) 的总和。由于此总和可能非常大,因此请取模 (10^9+7)
传送门

分析:

  以 (dp[i]) 表示 (gcd)(i) 的序列个数,([1,k])(i) 的倍数的个数为 (lfloor frac{k}{i} floor)。序列总数为:({lfloor frac{k}{i} floor}^n),同时由于会出现重复,所以要减去 (gcd)(i*2,i*3,...) 的情况,循环要从大到小。
  一开始直接减,发现有一部分多减了(具体见代码注释部分)。即当两个数均为 (i) 的倍数且倍数互质,那么二者的 (gcd) 仍为 (i),即序列中不一定要出现 (i)

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1e9+7;
const int N=1e5+5;
ll dp[N];
ll power(ll a,ll b)
{
    ll res=1;
    while(b)
    {
        if(b&1)
            res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res%mod;
}
int main()
{
    int n,k;
    ll ans=0;
    scanf("%d%d",&n,&k);
    for(int i=k;i>=1;i--)//以i为gcd
    {
        int tk=k/i;
        dp[i]=power(1LL*tk,1LL*n);
        for(int j=i*2;j<=k;j+=i)
            dp[i]-=dp[j];
        //ll t=power(1LL*tk,1LL*n)-power(1LL*(tk-1),1LL*n);cout<<i<<"="<<t<<endl;
        ans=(ans+dp[i]*i%mod+mod)%mod;//cout<<ans<<endl;
    }
    printf("%lld
",ans);
    return 0;
}

原文地址:https://www.cnblogs.com/1024-xzx/p/12719002.html