bzoj4407: 于神之怒加强版
懵逼乌斯反演裸题
画完柿子只要预处理S(i)=sigema(d|i)d u(i/d)*d^k
线性筛它一手
i%prime[j]!=0的话,首先i的因子也是i*prime[j]的因子,但是由于多了一个质因子所以正负性反过来。其次多了这个prime[j],i的所有因子都可以乘这个数,同样是它的因子,值的变化就是prime[j]^k。合起来S[i*prime[j]]=-S[i]+S[i]*prime[j]^k,结果亮老师一眼秒了S这个东西是一个积性函数,我一脸懵逼。。。想一想当是质数的时候,好像S值就是prime^k-1。。。然后百度一手发现这个是狄利克雷卷积的形式。。。好的扔了
i%prime[j]==0,我们换种表示方法,设i=x*p^q,对于S[i],有贡献的d,只能具有q或q-1个p,而对于i*prime[j]也就是x*p^(q+1)来说,有贡献的d是具有q+1或q个p的。而贡献,是d^k。那么前面的q对应后面的q+1,前面的q-1对应后面的q,要乘上的就是prime[j]^k
没取模好还挂了一次。。
#include<cstdio> #include<iostream> #include<cstring> #include<cstdlib> #include<algorithm> #include<cmath> using namespace std; typedef long long LL; const int mod=1e9+7; int K; int quick_pow(int A) { int ret=1;int p=K; while(p!=0) { if(p%2==1)ret=(LL)ret*A%mod; A=(LL)A*A%mod;p/=2; } return ret; } int pr,prime[5000010],u[5000010],mi[5000010],S[5000010]; bool v[5000010]; void get_prime() { pr=0;u[1]=1;mi[1]=1;S[1]=1; for(int i=2;i<=5000000;i++) { mi[i]=quick_pow(i); if(v[i]==false) { u[i]=-1,S[i]=(mi[i]-1+mod)%mod; prime[++pr]=i; } for(int j=1;j<=pr&&i*prime[j]<=5000000;j++) { v[i*prime[j]]=true; if(i%prime[j]==0) { u[i*prime[j]]=0,S[i*prime[j]]=(LL)S[i]*mi[prime[j]]%mod; break; } else u[i*prime[j]]=-u[i],S[i*prime[j]]=(LL)S[i]*S[prime[j]]%mod; } } for(int i=2;i<=5000000;i++)S[i]=(S[i]+S[i-1])%mod; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); int T; scanf("%d%d",&T,&K);get_prime(); while(T--) { int n,m,last,ans=0; scanf("%d%d",&n,&m); if(n>m)swap(n,m); for(int i=1;i<=n;i=last+1) { last=min(n/(n/i),m/(m/i)); ans=((LL)ans+(LL)(m/i)*(LL)(n/i)%mod*(LL)(S[last]-S[i-1]+mod)%mod)%mod; } printf("%d\n",ans); } return 0; }
pain and happy in the cruel world.