BZOJ 3944: Sum (杜教筛)
惊险…卡着时限过了…
注意有的地方可能爆int(因为有)
有几个地方可能会蜜汁RE,具体看代码注释
CODE
9000ms卡过2333
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int MAXN = 1000005;
int prime[MAXN/10], cnt;
LL mu[MAXN], phi[MAXN];
bool vis[MAXN];
inline void Pre_Work(int n) {
mu[1] = phi[1] = 1;
for(int i = 2; i <= n; ++i) {
if(!vis[i])
prime[++cnt] = i, mu[i] = -1, phi[i] = i-1;
for(int j = 1; j <= cnt && i*prime[j] <= n; ++j) {
vis[i*prime[j]] = 1;
if(i % prime[j] == 0) {
mu[i*prime[j]] = 0;
phi[i*prime[j]] = phi[i] * prime[j];
break;
}
mu[i*prime[j]] = -mu[i];
phi[i*prime[j]] = phi[i] * (prime[j]-1);
}
}
for(int i = 2; i <= n; ++i)
mu[i] += mu[i-1], phi[i] += phi[i-1];
}
map<int, int>MU;
int sum_mu(int n) {
if(n < MAXN) return mu[n];
if(MU.count(n)) return MU[n];
int re = 1;
for(int i = 2, j; i > 0 && i <= n; i = j+1) { //这里i=j+1会爆int
j = n/(n/i);
re -= (j-i+1) * sum_mu(n/i);
}
return MU[n]=re;
}
map<int, LL>PHI;
LL sum_phi(int n) {
if(n < MAXN) return phi[n];
if(PHI.count(n)) return PHI[n];
LL re = 1ll * n * (1ll*n+1) / 2; //这里+1也会爆int
for(int i = 2, j; i > 0 && i <= n; i = j+1) { //这里i=j+1会爆int
j = n/(n/i);
re -= sum_phi(n/i) * (j-i+1);
}
return PHI[n]=re;
}
int main() {
int n, T;
scanf("%d", &T);
Pre_Work(MAXN-1);
while(T--) {
scanf("%d", &n);
printf("%lld %d\n", sum_phi(n), sum_mu(n));
}
}