[luogu3396] 雜湊衝突
阿新 • • 發佈:2018-11-08
題意
思考
很早之前做的這一題,當時覺得這題的根號平衡思想很贊,現在重新回顧一遍,記錄下來。
簡要題意:給你 \(x,p\) ,從 \(x\) 開始,每隔 \(p\) 個數取一個數,求和
暴力的想法是直接列舉,計算,複雜度 \(O(n^2)\),當然我們也可以對答案進行簡單的預處理,令 \(ans[p][i]\) 表示模數是 \(p\),餘數是 \(i\)的答案,但預處理複雜度同樣是 \(O(n^2)\), 但我們實現 \(O(1)\) 詢問了,期望得分 \(10\)
我們得到的兩種演算法,第一種不用預處理,但詢問是 \(O(n^2)\) 的,第二種 \(O(n^2)\) 的預處理,但詢問是 \(O(1)\)
程式碼
#include<bits/stdc++.h> using namespace std; const int N = 150050; int read(){ int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x * f; } int n, m; int ans[110][110];/// ans[p][i] 對p取模 餘數為i int val[N], MAX, t; int query(int p, int la){ if(p <= t) return ans[p][la]; int ANS = 0; for(int i=la; i<=n; i+=p){ ANS += val[i]; } return ANS; } void change(int pos, int v){ for(int j=1; j<=t; j++){ ans[j][pos % j] = ans[j][pos % j] - val[pos] + v; } val[pos] = v; } int main(){ n = read(); m = read(); t = sqrt(n); for(int i=1; i<=n; i++) val[i] = read(); for(int i=1; i<=n; i++){ for(int j=1; j<=t; j++){ ans[j][i % j] += val[i]; } } while(m --){ char a; cin >> a; int x, y; cin >> x >> y; if(a == 'A'){ cout<<query(x, y)<<endl; } else change(x, y); } return 0; }
總結
本題的根號平衡思想真的很好,通過對小於 \(\sqrt n\) 和大於 \(\sqrt n\) 的範圍進行分治,將複雜度優化成根號