codeforces 7.22 F Pairwise Modulo
codeforces 7.22 F Pairwise Modulo
給出n個數的數列a,每個數互不相同且都小于3e5,求出qk=∑1<=i,j<=kaimodajq_k=\sum_{1<=i, j<=k}a_i~mod~a_jqk?=∑1<=i,j<=k?ai??mod?aj?
其中n <= 2e5
題意很簡單,就是求出前1到n個數兩兩之間相互取mod之后的和,但是拿到題的時候一點思路都沒有,靠著題解過活。
分析qkq_kqk?,可以將其分為兩個部分,一個是sks_ksk?,表示編號大的數mod編號小的數的和,另一個是tkt_ktk?,表示編號小的數mod編號大的數。這兩個部分可以分開分析然后求和。容易得到sk=sk?1+∑i=1k?1akmodais_k=s_{k-1}+\sum_{i=1}^{k-1}a_k~mod~a_isk?=sk?1?+∑i=1k?1?ak??mod?ai?,把mod拆成兩個部分akmodai=ak?ai?akai?a_k~mod~a_i=a_k-a_i\lfloor\frac{a_k}{a_i}\rfloorak??mod?ai?=ak??ai??ai?ak???,那么sk=sk?1+(k?1)ak?∑i=1k?1ai?akai?s_k=s_{k-1}+(k-1)a_k-\sum_{i=1}^{k-1}a_i\lfloor\frac{a_k}{a_i}\rfloorsk?=sk?1?+(k?1)ak??∑i=1k?1?ai??ai?ak???
關鍵就是最后面一個部分怎么求解。對于每個數aia_iai?,當它后面加入一個新的數aka_kak?時,這個部分對于答案的貢獻就是?ai?akai?-a_i\lfloor\frac{a_k}{a_i}\rfloor?ai??ai?ak???。所以,當我們在加入aia_iai?的時候,可以計算出對于其余可能出現的每一個數,對于答案的貢獻是多少。也就是,如果后面出現的數是0到ai?1a_i-1ai??1,那么貢獻為0;如果是aia_iai?到2ai?12a_i-12ai??1,那么貢獻是?ai-a_i?ai?;如果是2ai2a_i2ai?到3ai?13a_i-13ai??1,那么貢獻是?2ai-2a_i?2ai?,以此類推。這是一個區間修改,并且這個貢獻是可以疊加的,也就是說,它可以直接加在ai?1a_{i-1}ai?1?對于aka_kak?的貢獻上,當后面出現aka_kak?時,不用去糾結這個貢獻是ai?1a_{i-1}ai?1?還是aia_iai?所帶來的。這就可以想到用線段樹維護。
不過會發現,每一次加一個數進去會進行MAXNai\frac{MAXN}{a_i}ai?MAXN?次修改(MAXN==3e5),不過我們已經知道了aia_iai?兩兩互不相同。有一個結論:n/1+n/2+n/3+...+n/n=nlognn/1+n/2+n/3+...+n/n=n~lognn/1+n/2+n/3+...+n/n=n?logn
來自ccpc綿陽站的痛苦面具
而tkt_ktk?的轉化與sks_ksk?大同小異,sks_ksk?是區間修改單點查詢而tkt_ktk?是區間修改單點查詢。
這樣復雜度是O(nlog2MAXN)O(nlog^2MAXN)O(nlog2MAXN),是可以過的。不過我T了,應該是線段樹常數太大,今天不想改了,有空學一下非遞歸線段樹。
并且由于我們需要的操作是區間修改單點查詢和區間修改單點查詢,那么可以用樹狀數組來維護,常數會優秀很多。
貼的是T的代碼,感受一下原理即可。
更新:樹狀數組又好寫又快,換成樹狀數組的ac代碼了
const int N = 2e5 + 10, MAXN = 3e5 + 10;long long bitree[MAXN][2]; int a[N];inline int lowbit(int x) {return x & -x; }void change(int x, int d, int num) {while (x < MAXN){bitree[x][num] += d;x += lowbit(x);} }long long search(int x, int num) {long long ans = 0;while (x){ans += bitree[x][num];x -= lowbit(x);}return ans; }int main() {//freopen("in.txt", "r", stdin);//freopen("out.txt", "w", stdout);int T = 1;//T = read();while (T --){int n = read();long long ans = 0, sum = 0;for (int i = 1; i <= n; i ++){a[i] = read();ans += (long long)(i - 1) * a[i];ans += sum;ans -= search(a[i], 0);for (int j = a[i]; j < MAXN; j += a[i])ans -= (search(min(MAXN - 1, j + a[i] - 1), 1) - search(j - 1, 1)) * (j / a[i]) * a[i];sum += a[i];for (int j = a[i]; j < MAXN; j += a[i]){change(j, (j / a[i]) * a[i], 0);change(j + a[i], -(j / a[i]) * a[i], 0);}change(a[i], 1, 1);cout << ans;if (i < n) cout << " ";}}return 0; }總結
以上是生活随笔為你收集整理的codeforces 7.22 F Pairwise Modulo的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: RedisTemplate常用集合使用说
- 下一篇: matlab程序求尖锐度,业务名称