http://acm.hdu.edu.cn/showproblem.php?pid=6588
Find a new learned within the gcd of m and n and fast method for finding. That is below S1.
① requirements:
$ \sum\limits_{i=1}^{n}gcd(m,i) $
② enumeration d:
$ \sum\limits_{d|m} d \sum\limits_{i=1}^{n} [gcd(m,i)==d] $
Obviously ③:
$ \sum\limits_{d|m} d \sum\limits_{i=1}^{\lfloor\frac{n}{d}\rfloor} [gcd(\frac{m}{d},i)==1] $
This step has been to seek a recursively, Kiki said to be \ (O (the n-^ {\ FRAC {3} {4}}) \) , but the solution to a problem can continue down.
④ In order to facilitate a direct consideration $ \ sum \ limits_ {i = 1} ^ {n} [gcd (m, i) == 1] $, inversion (approximate):
$ \sum\limits_{i=1}^{n} \sum\limits_{d|gcd(m,i)} \mu(d) $
⑤ swap the order of enumeration d, it is clear that the contribution will be in multiples of n d within one mu (d):
$ \sum\limits_{d|m} \mu(d) \lfloor\frac{n}{d}\rfloor $
The following is based on the realization of the solution to a problem, but a version of __int64.
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef __int64 lll;
const int mod = 998244353;
const int MAXN = 10000000;
int phi[MAXN + 1];
int pri[MAXN + 1], pritop;
bool notpri[MAXN + 1];
void sieve() {
int n = MAXN;
pri[1] = phi[1] = 1;
for(int i = 2; i <= n; i++) {
if(!pri[i])
pri[++pritop] = i, phi[i] = i - 1;
for(int j = 1, tmp; j <= pritop && (tmp = i * pri[j]) <= n; j++) {
pri[tmp] = 1;
if(i % pri[j])
phi[tmp] = phi[i] * phi[pri[j]];
else {
phi[tmp] = phi[i] * pri[j];
break;
}
}
}
}
ll S1(lll n, int m) {
//sigma gcd(i,m) [1,n]
ll res = 0;
for(int T = 1; T * T <= m; ++T) {
if(!(m % T)) {
res += (n / T) * phi[T];
if(T * T != m) {
res += (n / (m / T)) * phi[(m / T)];
}
}
}
res %= mod;
return res;
}
ll qpow(ll x, int n) {
ll res = 1;
while(n) {
if(n & 1)
res = res * x % mod;
x = x * x % mod;
n >>= 1;
}
return res;
}
const int inv2 = qpow(2ll, mod - 2);
const int inv6 = qpow(6ll, mod - 2);
ll sigma1(ll x) {
return x * (x + 1ll) % mod * inv2 % mod;
}
ll sigma2(ll x) {
return x * (x + 1ll) % mod * (2ll * x + 1ll) % mod * inv6 % mod;
}
ll S2_1(int r, int T) {
int c = r / T;
ll res = 0;
res += 3ll * T * sigma2(c);
res += 3ll * sigma1(c);
res += c;
res %= mod;
return res;
}
ll S2(int r) {
ll res = 0;
for(int T = 1; T <= r; ++T) {
res += 1ll * phi[T] * S2_1(r, T) % mod;
}
res %= mod;
return res;
}
ll S0(lll n) {
lll i, i3;
for(i = 1;; ++i) {
lll tmp = i * i * i;
if(tmp > n) {
--i;
break;
} else
i3 = tmp;
}
ll res = 0;
res += S1(n, i) - S1(i3 - 1, i);
res += S2(i - 1);
res = (res % mod + mod) % mod;
return res;
}
inline lll read() {
lll x = 0;
char c;
do {
c = getchar();
} while(c < '0' || c > '9');
do {
x = (x << 3) + (x << 1) + c - '0';
c = getchar();
} while(c >= '0' && c <= '9');
return x;
}
int main() {
#ifdef Yinku
freopen("Yinku.in", "r", stdin);
#endif // Yinku
sieve();
int T;
cin >> T;
lll n;
while(T--) {
n = read();
cout << S0(n) << endl;
}
}
In fact, specific ideas or first divided into two parts to count, but I did not count the S1 led to a T.