P 3396 雜湊衝突 根號分治
阿新 • • 發佈:2020-09-17
據說這是一道論文題????。具體論文好像是 集訓隊論文《根號演算法——不只是分塊》
根號分治的裸題。
首先我們考慮暴力怎麼打。
- 先預處理出每個模數的答案,之後再 O(1) 的回答,修改預處理O(\(n^2\))
- 每次詢問直接暴力統計,修改是 O (1) 的,但回答是O(\(n^2\)) 的。
這兩種寫法都不能通過此題。
那我們想辦法把詢問和修改的複雜度均攤一下。
對於模數比較少的數,我們直接暴力統計的話,會涉及到的數比較多,這樣時間複雜度就上去了,所以我們採用方法一,來減少詢問的複雜度。
對於模數比較大·的數,我們就可以直接暴力回答,因為涉及到的數不會太多,這樣我們的複雜度是完全可以接受的。
我們一般把這個閾值設為 \(\sqrt{n}\) ,比這個數大的,我們認為他是比較大的模數,直接暴力統計答案的詢問最多涉及到 \({n \over {\sqrt n}} = \sqrt n\) 個數。
總的複雜度為 \(O((n+m)\sqrt n)\)
Code
#include<iostream> #include<cstdio> #include<algorithm> #include<cmath> using namespace std; #define LL long long int n,m,x,y,maxn,T,a[150010],f[400][400], ans; inline int read() { int s = 0,w = 1; char ch = getchar(); while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();} while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();} return s * w; } int main(){ n = read(); m = read(); T = sqrt(n); for(int i = 1; i <= n; i++) { a[i] = read(); for(int p = 1; p <= T; p++)//模數比較小的數,先預處理出答案來 { f[p][i % p] += a[i]; } } for(int i = 1; i <= m; i++) { char opt; cin>>opt; x = read(); y = read(); if(opt == 'A') { if(x <= T) printf("%d\n",f[x][y]);//模數小的數可以直接回答 else { ans = 0; for(int j = y; j <= n; j += x)//模數比較大的數暴力統計 { ans += a[j]; } printf("%d\n",ans); } } else if(opt == 'C') { for(int p = 1; p <= T; p++) { f[p][x % p] += y - a[x];//增量法對預處理的值修改 } a[x] = y; } } return 0; }