您的位置:首页 > 其它

【BZOJ3512】 DZY Loves Math IV

2017-01-20 14:09 561 查看
题意:(第n+1次)略

首先转换:Ans(n,m)=∑i=1n∑j=1mφ(i⋅j)设s(n,m)=∑i=1mφ(n⋅i)那么Ans(n,m)=∑i=1ns(i,m)每次从1到n枚举i,然后考虑:s(n,m)=∑i=1mφ(n⋅i)然后知道了一个听说很显然的东西:如果|μ(n)|=1那么φ(nk)=∑d|n,d|kφ(nd)φ(k)所以此时s(n,m)=∑k=1n∑d|n,d|kφ(nd)φ(k)=∑d|nφ(nd)∑k=1⌊md⌋φ(d⋅k)=∑d|nφ(nd)S(d,⌊md⌋)对于|μ(n)|=0找到最大的k|n使得|μ(k)|=0那么S(n,m)=n⋅S(k,m)k然后考虑S(1,m)=m⋅(m+1)2−∑i=2mS(1,⌊mi⌋)

杜教筛大力筛吧。然后递归求就好了。参考的大师的题解

注意:要记得记搜和map!!!!还有线性筛千万不要写错了(欧拉函数筛错的斯波在这里)

#include <bits/stdc++.h>
#define ll long long
#define N 2000009
#define mod 1000000007
using namespace std;
int n,M,pri
,pd
,cnt,phi
,Min
,Ans
,sum
;
map<ll,int>MAP;
int S(int n,int m)
{
if (m<=1) return phi[n*m];
if (n==1)
{
if (m<N) return sum[m];
if (Ans[M/m]!=-1) return Ans[M/m];
ll ans=(ll)m*(m+1)/2%mod;
for (int i=2,j;i<=m;i=j+1)
{
j=m/(m/i);
if (m/i<N) ans=ans-(ll)(j-i+1)*sum[m/i]%mod+mod;
else ans=ans-(ll)(j-i+1)*S(1,m/i)%mod+mod;
}
return Ans[M/m]=ans%mod;
}
else
{
if (MAP[(ll)n*mod+m]) return MAP[(ll)n*mod+m];
ll ans=0;
for (int i=1;i*i<=n;i++)
if (n%i==0)
{
ans=ans+(ll)phi[n/i]*S(i,m/i)%mod;
if (i*i!=n) ans=ans+(ll)phi[i]*S(n/i,m/(n/i))%mod;
}
return MAP[(ll)n*mod+m]=ans%mod;
}
}
int main()
{
ll ans=0;
scanf("%d%d",&n,&M);
memset(Ans,-1,sizeof Ans);
if (n>M) swap(n,M);
Min[1]=phi[1]=pd[1]=1;
for (int i=2;i<N;i++)
{
if (!pd[i]) pri[++cnt]=Min[i]=i,phi[i]=i-1;
for (int j=1;j<=cnt&&i*pri[j]<N;j++)
{
pd[i*pri[j]]=1;
if (i%pri[j]==0)
{
Min[pri[j]*i]=Min[i];
phi[i*pri[j]]=phi[i]*pri[j];
break;
}
phi[i*pri[j]]=phi[i]*(pri[j]-1);
Min[i*pri[j]]=Min[i]*pri[j];
}
}
for (int i=1;i<N;i++) sum[i]=(phi[i]+sum[i-1])%mod;
for (int i=1;i<=n;i++) ans=ans+((ll)i/Min[i]*S(Min[i],M)%mod);
printf("%lld\n",ans%mod);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: