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} \rfloor\)。序列总数为:\({\lfloor \frac{k}{i} \rfloor}^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\n",ans);
    return 0;
}

posted @ 2020-04-17 12:14  xzx9  阅读(171)  评论(0编辑  收藏  举报