[CQOI2017]小Q的表格
题目描述
给定一个表格,满足:
有次操作
- 每次操作修改的值,为了使整个表满足条件,所以要修改的点还挺多的
- 然后让你输出的范围内的数的和
Solution
对于性质,观察发现它可以转化一下:
对于转化到不太理解的同学,可以看看这个结论
这里就不细说了
所以可以得到一个结论:
为了方便后文描述,这里就记
那么就得到了一个线性的表了
那么再回头看看题目要求的问题
考虑:
所以原式可以化为:
那么这个时候我们发现,后面的是可以直接求解的(先预处理,就可以直接查询)
然而前面那个是会发生改变的
这个可以用树状数组或者是分块来维护
这两个理论上是可以过的,实测再loj是可以过的
某些上确实过不了的
时间复杂度理论上可以接受,具体能否跑过就靠评测姬了啊
Code(树状数组)
#include <bits/stdc++.h> #define lowbit(x) (x & -x) using namespace std; typedef long long ll; const ll maxn = 4e6 + 10; const ll mod = 1e9 + 7; inline ll __read() { ll x(0); char o(getchar()); while (o < '0' || o > '9') o = getchar(); for (; o >= '0' && o <= '9'; o = getchar()) x = ((x << 1) + (x << 3) + (o ^ 48)) % mod; return x % mod; } ll size, n, q, len; ll pr[maxn], phi[maxn], f[maxn], cnt; ll id[maxn], st[maxn], ed[maxn]; ll val[maxn], sum[maxn], Sum[maxn]; bool vis[maxn]; inline void inc(ll &x, ll y) { x += y; if (x >= mod) x -= mod; else if (x < 0) x += mod; } inline ll add(ll x, ll y) { ll temp = x + y; if (temp >= mod) temp -= mod; else if (temp < 0) temp += mod; return temp; } inline ll Pow(ll x, ll y) { ll ans(1); while (y) { if (y & 1) ans = ans * x % mod; x = x * x % mod; y >>= 1; } return ans % mod; } ll Gcd(ll x, ll y) { if (!y) return x; return Gcd(y, x % y); } inline void Update(ll x, ll val) { while (x <= n) { inc(sum[x], val); x += lowbit(x); } } inline ll Query(ll x) { ll ans(0); while (x) { inc(ans, sum[x]); x -= lowbit(x); } return ans % mod; } inline ll Query(ll l, ll r) { return add(Query(r), -1ll * Query(l - 1)); } inline void init() { phi[1] = 1; for (ll i = 2; i <= n; ++i) { if (!vis[i]) pr[++cnt] = i, phi[i] = i - 1; for (ll j = 1; j <= cnt && i * pr[j] <= n; ++j) { vis[i * pr[j]] = 1; if (i % pr[j]) { phi[i * pr[j]] = phi[i] * phi[pr[j]]; } else { phi[i * pr[j]] = phi[i] * pr[j]; break; } } } for (ll i = 1; i <= n; ++i) f[i] = (f[i - 1] + i * i % mod * phi[i] % mod) % mod; } signed main() { q = __read(), n = __read(); init(); for (ll i = 1; i <= n; ++i) { val[i] = 1ll * i * i % mod; Update(i, val[i]); } while (q--) { ll a = __read(), b = __read(), x = __read(), k = __read(), d = Gcd(a, b); ll upt = x * d % mod * d % mod * Pow(1ll * a * b % mod, mod - 2) % mod; Update(d, add(upt, -val[d])); val[d] = upt; ll ans(0); for (ll l = 1, r; l <= k; l = r + 1) { r = k / (k / l); inc(ans, f[k / l] * Query(l, r) % mod); } printf("%lld\n", ans); } }
Code(分块)
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll maxn = 4e6 + 10; const ll mod = 1e9 + 7; inline ll __read() { ll x(0); char o(getchar()); while (o < '0' || o > '9') o = getchar(); for (; o >= '0' && o <= '9'; o = getchar()) x = ((x << 1) + (x << 3) + (o ^ 48)) % mod; return x % mod; } ll size, n, q, len; ll pr[maxn], phi[maxn], f[maxn], cnt; ll id[maxn], st[maxn], ed[maxn]; ll val[maxn], sum[maxn], Sum[maxn]; bool vis[maxn]; inline void inc(ll &x, ll y) { x += y; if (x >= mod) x -= mod; } inline ll add(ll x, ll y) { ll temp = x + y; if (temp >= mod) temp -= mod; return temp; } inline ll Pow(ll x, ll y) { ll ans(1); while (y) { if (y & 1) ans = ans * x % mod; x = x * x % mod; y >>= 1; } return ans % mod; } ll Gcd(ll x, ll y) { if (!y) return x; return Gcd(y, x % y); } inline ll Get_sum(ll x) { if (!x) return 0; return add(Sum[id[x] - 1], sum[x]); } inline ll Get_sum(ll l, ll r) { return ((Get_sum(r) - Get_sum(l - 1)) % mod + mod) % mod; } inline void init() { phi[1] = 1; for (ll i = 2; i <= n; ++i) { if (!vis[i]) pr[++cnt] = i, phi[i] = i - 1; for (ll j = 1; j <= cnt && i * pr[j] <= n; ++j) { vis[i * pr[j]] = 1; if (i % pr[j]) { phi[i * pr[j]] = phi[i] * phi[pr[j]]; } else { phi[i * pr[j]] = phi[i] * pr[j]; break; } } } for (ll i = 1; i <= n; ++i) f[i] = (f[i - 1] + i * i % mod * phi[i] % mod) % mod; } inline void Update(ll x) { if (x == st[id[x]]) sum[x] = val[x]; else sum[x] = sum[x - 1] + val[x]; for (ll i = x + 1; i <= ed[id[x]]; ++i) sum[i] = add(sum[i - 1], val[i]); for (ll i = id[x]; i <= len; ++i) Sum[i] = add(Sum[i - 1], sum[ed[i]]); } signed main() { q = __read(), n = __read(); size = sqrt(n); init(); for (ll i = 1; i <= n; ++i) { id[i] = i / size + 1; if (i % size) continue; st[id[i]] = i, ed[id[i] - 1] = i - 1; } len = id[n], ed[id[n]] = n; for (ll i = 1; i <= n; ++i) val[i] = 1ll * i * i % mod; for (ll i = 1; i <= len; ++i) { sum[st[i]] = val[st[i]]; for (ll j = st[i] + 1; j <= ed[i]; ++j) sum[j] = add(sum[j - 1], val[j]); Sum[i] = add(Sum[i - 1], sum[ed[i]]); } while (q--) { ll a = __read(), b = __read(), x = __read(), k = __read(), d = Gcd(a, b); val[d] = x * d % mod * d % mod * Pow(1ll * a * b % mod, mod - 2) % mod; Update(d); ll ans(0); for (ll l = 1, r; l <= k; l = r + 1) { r = k / (k / l); inc(ans, f[k / l] * Get_sum(l, r) % mod); } printf("%lld\n", ans); } }
进一步考虑
我们每次修改的值其实是,所以真时要改的值并不多
那么我们可以先求出原表中范围内的值
再求出修改的值对答案贡献相对原来的偏移量
所以这个就是的复杂度
然后又是可以证明对于所有的的个数时处于这个级别的
所以修改大概就是
然而实际跑下来要比这快得多
Code
#include <bits/stdc++.h> using namespace std; typedef long long ll; const ll maxn = 4e6 + 10; const ll mod = 1e9 + 7; inline ll __read() { ll x(0); char o(getchar()); while (o < '0' || o > '9') o = getchar(); for (; o >= '0' && o <= '9'; o = getchar()) x = (x << 1) + (x << 3) + (o ^ 48); return x; } ll size, n, q, len; ll pr[maxn], phi[maxn], f[maxn], cnt; ll stk[maxn], upt[maxn], top; bool vis[maxn], che[maxn]; inline void init() { phi[1] = 1; for (ll i = 2; i <= n; ++i) { if (!vis[i]) pr[++cnt] = i, phi[i] = i - 1; for (ll j = 1; j <= cnt && i * pr[j] <= n; ++j) { vis[i * pr[j]] = 1; if (i % pr[j]) { phi[i * pr[j]] = phi[i] * phi[pr[j]]; } else { phi[i * pr[j]] = phi[i] * pr[j]; break; } } } for (ll i = 1; i <= n; ++i) f[i] = (f[i - 1] + i * i % mod * phi[i] % mod) % mod; } inline ll sum(ll x) { return x * (x + 1) / 2 % mod; } ll gcd(ll x, ll y) { if (!y) return x; return gcd(y, x % y); } signed main() { q = __read(), n = __read(); init(); while (q--) { ll a = __read(), b = __read(), x = __read(), k = __read(), d = gcd(a, b); upt[d] = x / (a / d) / (b / d) % mod; if (!che[d]) { stk[++top] = d; che[d] = 1; } ll ans(sum(k)); ans = ans * ans % mod; for (ll i = 1; i <= top; ++i) { d = stk[i]; ans = (ans + ((upt[d] - d * d % mod) % mod + mod) % mod * f[k / d] % mod) % mod; } printf("%lld\n", ans); } }