題解 P3601 【簽到題】
阿新 • • 發佈:2020-09-20
Solution 簽到題
題目大意:定義\(qiandao(n)=\sum_{i=1}^{n}[gcd(i,n)\neq1]\),求\(\sum_{i=l}^rqiandao(i)\),其中\(l,r\leq 10^{12},r-l \leq 10^6\)
數論
分析:首先\(qiandao(n)=n-\varphi(n)\)
所以我們考慮咋把\(\sum_{i=l}^{r}\varphi(i)\)求出來
把\([l,r]\)內每個數利用唯一分解定理分解,由於一個數\(n\)分解後的指數之和不會超過\(log_2n\),所以我們只需要求出這個數有哪些質因子,然後暴力求\(\varphi\)
我們篩出\([1,\sqrt{10^{12}}=10^6]\)內的所有質數,對於每個質數,將它在\([l,r]\)內的所有倍數打上標記
根據神尤拉給出的結論,這個的時間複雜度是\(nlogn\)級別的
於是我們得到了\([l,r]\)內每個數\(x\),小於\(\sqrt{x}\)的質因子,將它們的冪次全部除掉,得到的數如果不是\(1\),那它一定是一個大於\(\sqrt{x}\)的質因子,我們得到了\(x\)的所有質因子
然後愉快的求\(\varphi\)即可
#include <iostream> #include <vector> #include <cmath> using namespace std; typedef long long ll; const int maxn = 1e6 + 100,mod = 666623333; inline ll add(ll a,ll b){return (a + b) % mod;} bool vis[maxn]; vector<int> pri; inline void sieve(){ for(int i = 2;i < maxn;i++){ if(!vis[i])pri.push_back(i); for(int x : pri){ if(1ll * x * i >= maxn)break; vis[i * x] = 1; if(i % x == 0)break; } } } ll l,r,ans; vector<int> vec[maxn]; int main(){ sieve(); cin >> l >> r; for(int p : pri){ for(ll now = ceil((long double)l / p) * p;now <= r;now += p) vec[now - l].push_back(p); } for(ll now = l;now <= r;now++){ ll tmp = now,phi = 1; for(int p : vec[now - l]){ phi *= p - 1; tmp /= p; while((tmp % p) == 0){ phi *= p; tmp /= p; } } if(tmp != 1)phi *= tmp - 1; ans = add(ans,now - phi); } cout << ans << '\n'; return 0; }