luoguP4213 [模板]杜教篩
阿新 • • 發佈:2018-08-25
unsigned for () def -- std oid inline urn
https://www.luogu.org/problemnew/show/P4213
同 bzoj3944
考慮用杜教篩求出莫比烏斯函數前綴和,第二問隨便過,第一問用莫比烏斯反演來做,中間的整除分塊裏的莫比烏斯前綴和剛好用第二問來做
杜教篩的時候先線性篩出前 N 個數的莫比烏斯函數前綴和,其余的用 map 記憶化搜索,實測 N 取 3670000 最佳(其實我只測了3次)
#include <bits/stdc++.h> using namespace std; typedef unsigned long long ull; typedef long long ll; template <typename _T> inline void read(_T &f) { f = 0; _T fu = 1; char c = getchar(); while(c < '0' || c > '9') {if(c == '-') fu = -1; c = getchar();} while(c >= '0' && c <= '9') {f = (f << 3) + (f << 1) + (c & 15); c = getchar();} f *= fu; } const int N = 3670000; map <ll, ll> val; int mu[N], pri[N], isp[N], s[N], len = 0; int T, n; void Mu() { mu[1] = 1; for(int i = 2; i <= N - 10; i++) { if(!isp[i]) {pri[++len] = i; mu[i] = -1;} for(int j = 1; j <= len && i * pri[j] <= (N - 10); j++) { isp[i * pri[j]] = 1; if(i % pri[j] == 0) break; mu[i * pri[j]] = -mu[i]; } } for(int i = 1; i <= N - 10; i++) s[i] = s[i - 1] + mu[i]; } ll getmu(ll n) { if(n <= N - 10) return (ll)s[n]; if(val.count(n)) return val[n]; ll ans = 0; for(ll l = 2, r; l <= n; l = r + 1) { r = n / (n / l); ans += (r - l + 1) * getmu(n / l); } val[n] = 1 - ans; return val[n]; } ll getphi(ll n) { ll ans = 0; for(ll l = 1, r; l <= n; l = r + 1) { r = n / (n / l); ans += (getmu(r) - getmu(l - 1)) * (n / l) * (n / l); } return (ans + 1) >> 1; } int main() { read(T); Mu(); while(T--) { read(n); printf("%lld %lld\n", getphi(n), getmu(n)); } return 0; }
luoguP4213 [模板]杜教篩