您的位置:首页 > 其它

于神之怒

2016-01-08 19:37 351 查看

题目大意

求∑ni=1∑mj=1gcd(i,j)k

n,m,k<=5000000

繁衍

设h[i]=ik,显然h可以线筛出来。

设n<=m如果不小于就调换。

设f[d]=∑ni=1∑mj=1(gcd(i,j)==d)

那么显然f[d]=∑⌊nd⌋i=1∑⌊md⌋j=1(gcd(i,j)==1)

这意味着我们进行分块,每一块的f值都相同。

ans=∑nd=1f[d]∗h[d]

容易想到求f使用莫比乌斯反演,于是

f[d]=∑⌊nd⌋i=1⌊nd∗i⌋∗⌊md∗i⌋∗μ[i]

那么同样进行分块,每一块的⌊nd∗i⌋∗⌊md∗i⌋一样。

所以线筛出h与μ即可。

参考程序

#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef long long ll;
const ll mo=1000000007;
ll mu[5000000+10],pri[1000000],h[5000000+10],sum[5000000+10],num[5000000+10];
bool bz[5000000+10];
ll i,j,k,l,r,t,n,m,nn,mm,p,top,tot,ans;
ll quicksortmi(ll x,ll y){
if (!y) return 1;
ll t=quicksortmi(x,y/2);
t=t*t%mo;
if (y%2) t=t*(x%mo)%mo;
return t;
}
ll min(ll a,ll b){
if (a<b) return a;else return b;
}
int main(){
//freopen("D:/wa.txt","w",stdout);
scanf("%lld%lld%lld",&n,&m,&p);
if (n>m) swap(n,m);
top=0;
mu[1]=h[1]=1;
fo(i,2,n){
if (!bz[i]){
pri[++top]=i;
mu[i]=-1;
h[i]=quicksortmi(i,p);
}
fo(j,1,top){
if (i*pri[j]>n) break;
h[i*pri[j]]=1LL*h[i]*h[pri[j]]%mo;
bz[i*pri[j]]=1;
if (i%pri[j]==0) break;
mu[i*pri[j]]=-mu[i];
}
}
sum[0]=num[0]=0;
fo(i,1,n) num[i]=num[i-1]+mu[i],sum[i]=(sum[i-1]+h[i])%mo;
i=1;
while (i<=n){
j=min(n/(n/i),m/(m/i));
nn=n/i,mm=m/i;
k=1;r=0;
while (k<=nn){
l=min(nn/(nn/k),mm/(mm/k));
r=((nn/k)*(mm/k)%mo*(num[l]-num[k-1])%mo+r)%mo;
k=l+1;
}
t=(sum[j]-sum[i-1])%mo;
r=r*t%mo;
ans=(ans+r)%mo;
i=j+1;
}
printf("%lld\n",ans);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: