传送门
2 4 5
82 354HintCase1: sum=1+3*3*3*3=82 Case2: sum=1+2*2*2*2+3*3*3*3+4*4*4*4=354
给定 T 组数据,每组数据一个数 n ,然后让你求 <n且与 n 互素的数的四次方,详见样例。
解题思路:
就是就一个 S = a1^4 + a2^4 + ... + ak^4;
这个我们可以考虑容斥原理:也就是 1^4 + 2^4 + 3^4 + ... + n^4 - 不互素的数的四次方。
然后遇到了一个 很严重的问题 就是 1^4 + 2^4 + 3^4 + ... + n^4怎么求;
首先 要推一下Sum = 1 + 2 + 3 + ... +n
(n+1)^2 - n^2 = 2*n+1;
n^2 - (n-1)^2 = 2*(n-1)+1;
...
3^2 - 2^2 = 2*2+1;
2^2 - 1^2 = 2*1+1;
将上述等式 左边加左边 右边加右边得到:
(n+1)^2 - 1 = 2*(1+2+3+...+n)+n*1;
又因为 我们所求 Sum = 1 + 2 + 3 + ... +n;
所以:2*Sum + n = (n+1)^2-1 =n^2+2*n+1-1 = n^2+2*n;
Sum = (n^2+n)/2;
所以 我们要求的四次方之和 就得用到 (n+1)^5 - n^5;(三次方的公式 首先得知道 就是通过刚才那个推出来的)
(x+1)^5 = x^5+5*x^4+10*x^3+10*x^2+5*x+1;
推完之后就是下面这个公式 还是挺费事儿的:
(1^4+2^4+……+n^4)=(n*(n+1)*(2n+1)*(3*n*n+3*n-1))/30;在这里 我们还要求一下 30 关于 MOD = 1e9+7的逆元,这个可以通过扩展欧几里得算法实现...
然后 就是 分析一下 代码的实现过程了:
第一步:我们首先进行素数筛 ;
第二步:我们就要进行素因子分解;
第三步:写一个快速幂 计算 X^4对 MOD取模
第四步:二进制枚举 ,奇加偶减;
完事儿。
My Code:
#include <iostream> #include <cstdio> #include <cstring> using namespace std; typedef long long LL; const LL MOD = 1e9+7; const LL MAXN = 1e6+5; LL Scan()///输入外挂 { LL res=0,ch,flag=0; if((ch=getchar())=='-') flag=1; else if(ch>='0'&&ch<='9') res=ch-'0'; while((ch=getchar())>='0'&&ch<='9') res=res*10+ch-'0'; return flag?-res:res; } inline void Out(LL a)///输出外挂 { if(a>9) Out(a/10); putchar(a%10+'0'); } LL n; /** void Ex_gcd(int a, int b, int &x, int &y) { if(b == 0) { x = 1; y = 0; return; } int x1, y1; Ex_gcd(b, a%b, x1, y1); x = y1; y = x1 - (a/b)*y1; }**/ bool prime[MAXN]; int p[MAXN]; LL k; void isprime() { memset(prime, false, sizeof(prime)); k = 0; for(LL i=2; i<MAXN; i++) { if(!prime[i]) { p[k++] = i; for(LL j=i*i; j<MAXN; j+=i) prime[j] = true; } } } int fac[MAXN/100], num[MAXN/100]; LL cnt; void Dec(LL m) { cnt = 0; memset(num, 0, sizeof(num)); for(LL i=0; i<k&&p[i]*p[i]<=m; i++) { if(m%p[i] == 0) { fac[cnt] = p[i]; while(m%p[i]==0) { m /= p[i]; num[cnt]++; } cnt++; } } if(m > 1) { fac[cnt] = m; num[cnt++] = 1; } /**cout<<cnt<<endl; for(int i=0; i<cnt; i++) cout<<fac[i]<<" ";*/ } LL Get_ans(LL x) { LL ans = x%MOD; ans = ans*(x+1)%MOD; ans = ans*(x+x+1)%MOD; ans = ans*((3*x*x+3*x-1)%MOD)%MOD; ans = ans*233333335%MOD;///233333335是逆元 return ans; } LL quick_mod(LL a, LL b) { LL ans = 1; while(b) { if(b & 1) ans = ans*a%MOD; b>>=1; a = a*a%MOD; } return ans%MOD; } int main() { isprime(); ///Dec(6); ///int x, y; ///Ex_gcd(30,MOD, x, y) int T; T = Scan(); while(T--) { n = Scan(); Dec(n); LL res = 0; for(LL i=1; i<(1<<cnt); i++) { LL ans = 1, sum = 0; for(LL j=0; j<cnt; j++) { if(i & (1<<j)) { sum++; ans = ans*fac[j]%MOD; } } if(sum&1) res = (res+Get_ans(n/ans)*quick_mod(ans,4)+MOD)%MOD; else res = (res-Get_ans(n/ans)*quick_mod(ans,4)+MOD)%MOD; } res = (Get_ans(n)-res+MOD)%MOD; res=(res%MOD+MOD)%MOD; printf("%lld\n",res); } return 0; }