[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);
}
} 
京公网安备 11010502036488号