题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4059
题目大意:
给一个n,求1~n中与n互质的数的4次方的总和。
解题思路:
容斥原理、逆元、公式。
其实是蛮简单的一道题。囧囧。
首先必须知道1^4+2^4+...+n^4=n*(n+1)*(2n+1)(3n^2+3n-1)/30. 除以30可以转化成乘以30的逆元,30^(M-2) 由费马小定理很快可以得到。
先求出1^4+2^4+...+n^4然后减去与n不互质的。 假设n=p1^a1*p2^a2...pn^an 用容斥原理先减去含一个质因数的所有的不超过n的倍数,然后加上含两个质因数的,然后减去含三个质因数的。一个dfs就可以搞定。
代码:
#include<iostream> #include<cmath> #include<cstdio> #include<cstdlib> #include<string> #include<cstring> #include<algorithm> #include<vector> #include<map> #include<set> #include<stack> #include<list> #include<queue> #define eps 1e-6 #define INF 0x1f1f1f1f #define PI acos(-1.0) #define ll __int64 #define lson l,m,(rt<<1) #define rson m+1,r,(rt<<1)|1 #pragma comment(linker, "/STACK:1024000000,1024000000") #define M 1000000007 using namespace std; //freopen("data.in","r",stdin); //freopen("data.out","w",stdout); ll pp[10]; //10个就够了 ll cnt,n,sum,mm; ll quick(ll a,ll b) //快速幂求 a^b mod M 求30的逆元 { ll res=1; while(b) { if(b&1) res=(res*a)%M; a=(a*a)%M; b>>=1; } return res; } ll Four(ll k) //1^4+2^4+...+n^4 { return ((((k*(k+1))%M*(2*k+1))%M*((3*k*k%M+3*k-1)%M))%M*mm)%M; } void Cal(ll a,ll flag) //求出含有质因数乘积为a的所有的小于n的倍数 { ll k=n/a; //a^4+(2a)^4+(3a)^4+...(k*a)^4=a^4*(1^4+2^4+...+k^4) ll res=1; for(int i=1;i<=4;i++) //求出a的四次方 res=(res*a)%M; res=(res*Four(k))%M; //求出1~k的四次方和 if(flag&1) //容斥原理 sum=((sum-res)%M+M)%M; else sum=(sum+res)%M; } void dfs(ll la,ll pos,ll num) //la表示前面的质因数的乘积,pos表示当前的质因数编号,num表示加还是减 { if(pos>cnt) return ; for(int i=pos;i<=cnt;i++) { Cal(la*pp[i],num); // dfs(la*pp[i],i+1,num+1); } } int main() { int t; scanf("%d",&t); mm=quick(30,M-2); //先求一下逆元 while(t--) { scanf("%I64d",&n); cnt=0; ll nn=n; sum=Four(n); //求出总的 for(int i=2;i*i<=nn;i++) //分解质因数 √n的时间复杂度 { if(nn%i==0) { pp[++cnt]=i; while(nn%i==0) nn/=i; } } if(nn!=1) pp[++cnt]=nn; dfs(1,1,1); printf("%I64d ",sum); } return 0; }