题目大意是求1-n中与n互质的数的四次方累加。
由于正解比较麻烦,所以我们可以先求出1-n的前n个四次方累加,减去跟n不是互质的数的四次方
1-n的四次方累加和公式 = n*(n+1)*(2*n+1)*(3*n*n+3*n-1)/30
先将n的质因数求出,然后比n小的并且是质因数的倍数的数的四次方 ,由于会多减去一些数,因此要用到容斥定理。
例如2 的倍数有2,4,6,8 。3 里面的倍数也有6,因此会多减。
2的倍数四次方可以提取出来2的次数方,并用1-n/2的四次方累加和公式。
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<vector> using namespace std; #define MOD 1000000007 #define ll long long const int maxn = 1e4 + 5; vector<ll> q; int prime[maxn]; int vis[maxn]; int cnt; ll pow_k(ll a, ll b) { ll res = 1; while(b) { if(b & 1) res =(res*a) % MOD; a = (a*a)%MOD; b >>= 1; } return res%MOD; } ll pow_f(ll x) { ll res = (x*x) % MOD; res = (res * x) %MOD; res = (res * x) % MOD; return res % MOD; } ll sum(ll n) { ll res = pow_k(30, MOD-2); ll s = n*(n+1) % MOD; s = (s*(2*n+1)%MOD) % MOD; s = (s*(3*n*n%MOD + 3*n%MOD-1+MOD)%MOD) % MOD; s = (s*res) % MOD; return s%MOD; } ll dfs(int index, ll n) { ll res = 0, temp; int len = q.size(); for(int i = index; i< len; i++) { temp = q[i]; res = (res + sum(n/temp)*pow_f(temp)%MOD) % MOD; res = (res - dfs(i+1, n/temp)*pow_f(temp)% MOD + MOD) % MOD; } return res % MOD; } void is_prime() { memset(vis, 0, sizeof vis); for(int i = 2; i <= maxn; i ++) { if(vis[i]) continue ; prime[cnt++] = i; for(int j = i*i; j <= maxn; j+=i) vis[j] = 1; } } int main() { int t; scanf("%d", &t); while(t--) { cnt = 0; is_prime(); ll n; q.clear(); scanf("%lld", &n); ll temp = n; for(int i = 0; i < cnt && prime[i] < temp; i++) if(temp%prime[i] == 0) { q.push_back(prime[i]); while(temp%prime[i] == 0) temp /= prime[i]; } if(temp != 1) q.push_back(temp); ll res = 0; int size = q.size(); for(int i = 1; i < (1 << size); i++) // 容斥原理 { int flag = 0; temp = 1; for(int j = 0; j < size; j++) { if(i & (1 << j)) temp = (temp*q[j]) % MOD,flag = !flag; } ll t = (sum(n/temp)*pow_f(temp)) % MOD; if(flag) res = (res + t) % MOD; else res = (res - t + MOD) % MOD; } printf("%lld\n", (sum(n)-res + MOD) % MOD); //ll res = (sum(n) - dfs(0, n)%MOD + MOD) % MOD; //cout << res << endl; // dfs 是递归式 实现容斥原理 } return 0; }