容斥原理是计数中常用的一种方法。在讨论容斥原理的过程中,要用到以下集合论的基本性质。
德摩根(De Morgan)定理
若A和B是集合U的子集,则
题意:给一个数n(n=10^8),求X1^4+X2^4+..Xk^4的和模1,000,000,007,其中1<=Xi<n,且Xi与n互素。
解:
四次方求和公式为:n*(n+1)*(2*n+1)*(3*n*n+3*n-1)/30
将n分解素因子为p1^e1*p2^e2*..*pk^ek,设集合Ai为pi的整数倍的数的集合。则答案为U-|A1UA2U...UAk|。
求|A1UA2U...UAk|即可用容斥原理求解。
注意先求30在模1,000,000,007下的逆元。
时间复杂度分析:
n为10^8,素因子分解最多有10个左右,容斥原理求解计算次数大约为2^10,复杂度已经很低了。
#include<cstdio>
#include<cstring>
typedef long long ll;
const ll MOD=1000000007;
const int nPri=10005;
ll factor[64],res;
int prime[nPri],cnt;
bool is_pri[nPri];
void Prime()
{
memset(is_pri,1,sizeof(is_pri));
cnt=0;
int i,j;
for(i=2;i<nPri;i++)
{
if(is_pri[i])
{
prime[cnt++]=i;
for(j=i+i;j<nPri;j+=i)
{
is_pri[j]=false;
}
}
}
}
ll PowMode(ll a,ll b)
{
ll ret=1;
while(b)
{
if(b&1)
{
ret=(ret*a)%MOD;
}
a=(a*a)%MOD;
b>>=1;
}
return ret;
}
int getFactor(ll n)
{
int i,count=0;
for(i=0;i<cnt;i++)
{
if(n<prime[i])
{
break;
}
if(n%prime[i]==0)
{
factor[count++]=prime[i];
while(n%prime[i]==0)
{
n/=prime[i];
}
}
}
if(n!=1)
{
factor[count++]=n;
}
return count;
}
ll get_sum(ll n)
{
ll ans=n;
ans=(ans*(n+1))%MOD;
ans=(ans*(2*n+1))%MOD;
ans=(ans*((3*n*n+3*n-1)%MOD))%MOD;
ans=(ans*res)%MOD;
return ans;
}
ll dfs(ll n,int start,int count) //容斥原理
{
ll ans=0;
int i;
for(i=start;i<count;i++)
{
ll temp=PowMode(factor[i],4);
ans=(ans+ (temp*get_sum(n/factor[i]))%MOD-
(temp*dfs(n/factor[i],i+1,count))%MOD + MOD)%MOD;
}
return ans;
}
int main()
{
Prime();
res=PowMode(30,MOD-2);
int T;
scanf("%d",&T);
while(T--)
{
ll n;
scanf("%I64d",&n);
int count=getFactor(n);
ll ans=(get_sum(n)-dfs(n,0,count)+MOD)%MOD;
printf("%I64d\n",ans);
}
return 0;
}