P3700 [CQOI2017]小Q的表格
给定一个大小为n×nn \times nn×n的表格,初始时i,ji, ji,j位置上填的是f(i,j)=i×jf(i, j) = i \times jf(i,j)=i×j,有mmm个操作,每次操作给定a,b,x,ka, b, x, ka,b,x,k,把格子a,ba, ba,b上的值改成xxx,求∑i=1k∑j=1kf(i,j)\sum\limits_{i = 1} ^{k} \sum\limits_{j = 1} ^{k} f(i, j)i=1∑kj=1∑kf(i,j)。
我们定义,在任何时刻,表格里的值都满足f(i,j)=f(j,i),j×f(i,i+j)=(i+j)×f(i,j)f(i, j) = f(j, i), j \times f(i, i + j) = (i + j) \times f(i, j)f(i,j)=f(j,i),j×f(i,i+j)=(i+j)×f(i,j)。
b×f(a,a+b)=(a+b)×f(a,b)f(a,a+b)a×(a+b)=f(a,b)a×bf(a,b)a×b=f(b,a%b)b×a%bf(a,b)a×b=f(d,d)d×d,d=gcd(a,b)f(a,b)=a×bd×df(d,d)b \times f(a, a + b) = (a + b) \times f(a, b)\\ \frac{f(a, a + b)}{a \times (a + b)} = \frac{f(a, b)}{a \times b}\\ \frac{f(a, b)}{a \times b} = \frac{f(b, a\ \%\ b)}{b \times a\ \%\ b}\\ \frac{f(a, b)}{a \times b} = \frac{f(d, d)}{d \times d}, d = \gcd(a, b)\\ f(a, b) = \frac{a \times b}{d \times d} f(d, d)\\ b×f(a,a+b)=(a+b)×f(a,b)a×(a+b)f(a,a+b)=a×bf(a,b)a×bf(a,b)=b×a % bf(b,a % b)a×bf(a,b)=d×df(d,d),d=gcd(a,b)f(a,b)=d×da×bf(d,d)
考虑统计答案:
∑i=1n∑j=1nf(i,j)∑d=1nf(d,d)∑i=1nd∑j=1ndij[gcd(i,j)=1]∑d=1nf(d,d)(∑i=1ndi∑j=1ij[gcd(i,j)−1]−1)∑d=1nf(d,d)∑i=1ndi2ϕ(i)g(n)=∑i=1ni2×ϕ(i)\sum_{i = 1} ^{n} \sum_{j = 1} ^{n} f(i, j)\\ \sum_{d = 1} ^{n} f(d, d) \sum_{i = 1} ^{\frac{n}{d}} \sum_{j = 1} ^{\frac{n}{d}} ij[\gcd(i, j) = 1]\\ \sum_{d = 1} ^{n} f(d, d) \left(\sum_{i = 1} ^{\frac{n}{d}} i \sum_{j = 1} ^{i} j[\gcd(i, j) - 1] - 1\right)\\ \sum_{d = 1} ^{n} f(d, d) \sum_{i = 1} ^{\frac{n}{d}} i ^ 2 \phi(i)\\ g(n) = \sum_{i = 1} ^{n} i ^ 2 \times \phi(i)\\ i=1∑nj=1∑nf(i,j)d=1∑nf(d,d)i=1∑dnj=1∑dnij[gcd(i,j)=1]d=1∑nf(d,d)⎝⎛i=1∑dnij=1∑ij[gcd(i,j)−1]−1⎠⎞d=1∑nf(d,d)i=1∑dni2ϕ(i)g(n)=i=1∑ni2×ϕ(i)
容易发现g(n)g(n)g(n)可以线性筛得到,所以我们只要动态维护f(d,d)f(d, d)f(d,d)的前缀和即可,考虑用分块维护前缀和,满足n\sqrt nn修改,O(1)O(1)O(1)查询。
#include <bits/stdc++.h>using namespace std;const int N = 4e6 + 10, mod = 1e9 + 7;int prime[N], phi[N], g[N], f[N], cnt, n, m;int L[N], R[N], id[N], sum[N], lazy[N], block, blocks;bool st[N];inline int add(int x, int y) {return x + y < mod ? x + y : x + y - mod;
}inline int sub(int x, int y) {return x >= y ? x - y : x - y + mod;
}void init() {phi[1] = 1;for (int i = 2; i < N; i++) {if (!st[i]) {prime[++cnt] = i;phi[i] = i - 1;}for (int j = 1; j <= cnt && 1ll * i * prime[j] < N; j++) {st[i * prime[j]] = 1;if (i % prime[j] == 0) {phi[i * prime[j]] = phi[i] * prime[j];break;}phi[i * prime[j]] = phi[i] * (prime[j] - 1);}}for (int i = 1; i < N; i++) {g[i] = add(g[i - 1], 1ll * i * i % mod * phi[i] % mod);f[i] = 1ll * i * i % mod, sum[i] = add(sum[i - 1], f[i]);}block = sqrt(n);for (int i = 1; i <= n; i += block) {L[++blocks] = i, R[blocks] = min(i + block - 1, n);for (int j = L[blocks]; j <= R[blocks]; j++) {id[j] = blocks;}}
}inline int query(int x) {return add(sum[x], lazy[id[x]]);
}inline void update(int x, int v) {int pos = id[x];for (int i = x; i <= R[pos]; i++) {sum[i] = add(sum[i], v);}pos++;while (pos <= blocks) {lazy[pos] = add(lazy[pos], v);pos++;}
}int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);scanf("%d %d", &m, &n);init();for (int cas = 1, a, b, k; cas <= m; cas++) {long long x;scanf("%d %d %lld %d", &a, &b, &x, &k);int p = __gcd(a, b);update(p, sub(0, f[p]));f[p] = (x / (a / p)) / (b / p) % mod;update(p, f[p]);int ans = 0;for (int l = 1, r; l <= k; l = r + 1) {r = k / (k / l);ans = add(ans, 1ll * g[k / l] * sub(query(r), query(l - 1)) % mod);}printf("%d\n", ans);}return 0;
}