Luogu P3312 [SDOI2014]數表
阿新 • • 發佈:2020-07-22
設\(\sigma(i)\)表示\(i\)的因子之和。
\(\sum\limits_{i=1}^n\sum\limits_{j=1}^m\sigma(gcd(i,j))\ [\sigma(gcd(i,j))\le a]\)
\(\sum\limits_{k=1}^n\sigma(k)\sum\limits_{i=1}^{\frac{n}{k}}\sum\limits_{j=1}^{\frac{m}{k}}\sum_{d|gcd(i,j)}\mu(d)\ [\sigma(k)\le a]\)
\(\sum\limits_{k=1}^n\sigma(k)\sum\limits_{d=1}^{\frac{n}{k}}\mu(d)\lfloor\frac{n}{kd}\rfloor\lfloor\frac{m}{kd}\rfloor\ [\sigma(k)\le a]\)
設\(T=kd\)
\(\sum\limits_{T=1}^n\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{d|T}\mu(d)\times\sigma(\frac{T}{d})\ [\sigma(\frac{T}{d})\le a]\)
設\(f(T,a) = \sum_{d|T}\mu(d)\times\sigma(\frac{T}{d})\ [\sigma(\frac{T}{d})\le a]\)
預處理出\(\sigma(x)\).
將詢問離線,按\(a\)從小到大排序。
每次遇到一個詢問時,更新所有\(\sigma(x)<a\)
\(\sigma(x)\)會對\(f(x,a),f(2x,a),f(3x,a),...\)產生影響,貢獻即為\(\mu(i)*\sigma(x) (ix=T,x=\frac{T}{i})\)
因為要求字首和,\(f(x)\)可以用樹狀陣列維護。
時間複雜度\(O(n \log^2 n +q\sqrt n \log n)\)
吸氧可過
code
#include<cstdio> #include<iostream> #include<cmath> #include<cstring> #include<algorithm> #define MogeKo qwq using namespace std; const int maxn = 1e5+10; const int N = 1e5; const int mod = 1ll<<31; int Q,now,cnt; int prime[maxn],mu[maxn]; long long sig[maxn],tree[maxn],ans[maxn]; bool vis[maxn]; struct node { long long x,y,z,id; bool operator < (const node &N) const { return z < N.z; } } q[maxn],d[maxn]; long long read() { long long x = 0,f = 1; char ch = getchar(); while(ch < '0' || ch > '9') { if(ch == '-') f = -1; ch = getchar(); } while('0' <= ch && ch <= '9') { x = x*10 + ch-'0'; ch = getchar(); } return x*f; } void Prime() { mu[1] = 1; for(int i = 2; i <= N; i++) { if(!vis[i]) { prime[++cnt] = i; mu[i] = -1; } for(int j = 1; j <= cnt && i*prime[j] <= N; j++) { vis[i*prime[j]] = true; if(i % prime[j] == 0) break; mu[i*prime[j]] = -mu[i]; } } for(int i = 1; i <= N; i++) { for(int j = 1; i*j <= N; j++) sig[i*j] += i; d[i].z = sig[i]; d[i].id = i; } sort(d+1,d+N+1); } int lowbit(int x) { return x & (-x); } void add(int x,int k) { for(; x <= N; x += lowbit(x)) tree[x] += k; } long long query(int x) { long long num = 0; for(; x; x -= lowbit(x)) num += tree[x]; return num; } void modify(int x) { for(int i = 1; i*x <= N; i++) add(i*x,mu[i]*sig[x]); } long long solve(int x,int y) { int num = 0; if(x > y) swap(x,y); for(int i = 1,r; i <= x; i = r+1) { r = min(x/(x/i), y/(y/i)); num += (long long)(x/i) * (y/i) * (query(r) - query(i-1)); } return num % mod; } int main() { Q = read(); for(int i = 1; i <= Q; i++) { q[i].x = read(), q[i].y = read(), q[i].z = read(); q[i].id = i; } sort(q+1,q+Q+1); Prime(); now = 0; for(int i = 1; i <= Q; i++) { while(d[now+1].z <= q[i].z && now < N) modify(d[++now].id); ans[q[i].id] = solve(q[i].x,q[i].y); } for(int i = 1; i <= Q; i++) printf("%lld\n",ans[i]); return 0; }