P3700 [CQOI2017]小Q的表格
P3700 [CQOI2017]小Q的表格
有一个表格,满足:
且一开始 ,然后带上一个单点修改操作。
每当修改了一个格子的数之后,为了让表格继续满足上述两个条件,你还需要把这次修改能够波及到的全部格子里都改为恰当的数。
你还需要随时输出前 行前 列这个有限区域内所有数的和 。
考虑从下面那个式子得出一些可以反演的东西,有:
设 ,则有:
考虑到这个矩阵要变换,因为修改一个位置 的值后有且仅有 的 位置的 值会跟着变化,那么用一个树状数组维护 即可。
设 ,再考虑答案:
设 ,则原式等于:
根据 ,有:
那么有:
那么原式等于:
线性筛,维护前缀和,再数论分块即可。
#include <bits/stdc++.h>
using namespace std;
#define int long long
const int mod = 1e9 + 7;
inline int read()
{
int x = 0, f = 1;
char c = getchar();
while(c < '0' || c > '9')
{
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9')
{
x = ((x << 1) + (x << 3) + (c ^ 48)) % mod;
c = getchar();
}
return x * f;
}
inline void write(int x)
{
if(x < 0)
{
putchar('-');
x = -x;
}
if(x > 9)
write(x / 10);
putchar(x % 10 + '0');
}
const int _ = 4e6 + 10;
int n, m;
int cnt, pr[_], vis[_], phi[_];
int f[_];
int c[_];
int val[_];
int Gcd(int x, int y)
{
if (!y)
return x;
return Gcd(y, x % y);
}
void inc(int &x, int y)
{
x += y;
if(x >= mod) x -= mod;
else if(x < 0) x += mod;
}
int add(int x, int y)
{
int temp = x + y;
if (temp >= mod)
temp -= mod;
else if (temp < 0)
temp += mod;
return temp;
}
int qpow(int x, int y)
{
int res = 1;
while(y)
{
if(y & 1) res = res * x % mod;
x = x * x % mod;
y >>= 1;
}
return res;
}
void init()
{
phi[1] = 1;
for(int i = 2; i <= n; ++i)
{
if(!vis[i])
{
pr[++cnt] = i;
phi[i] = i - 1;
}
for(int j = 1; j <= cnt && i * pr[j] <= n; ++j)
{
vis[i * pr[j]] = 1;
if(i % pr[j] == 0)
{
phi[i * pr[j]] = phi[i] * pr[j];
break;
}
phi[i * pr[j]] = phi[i] * (pr[j] - 1);
}
}
for(int i = 1; i <= n; ++i)
f[i] = (f[i - 1] + i * i % mod * phi[i] % mod) % mod;
}
#define lowbit(x) (x & -x)
void update(int x, int val)
{
while(x <= n)
{
inc(c[x], val);
x += (x & -x);
}
}
int query(int x)
{
int res = 0;
while(x)
{
inc(res, c[x]);
x -= (x & -x);
}
return res;
}
int Query(int l, int r)
{
return add(query(r), -query(l - 1));
}
signed main()
{
m = read(), n = read();
init();
for(int i = 1; i <= n; ++i)
{
val[i] = i * i % mod;
update(i, val[i]);
}
while(m--)
{
int a = read(), b = read(), x = read(), k = read(), d = Gcd(a, b);
int upt = x * d % mod * d % mod * qpow(a * b % mod, mod - 2ll) % mod;
update(d, add(upt, -val[d]));
val[d] = upt;
int ans = 0;
int S = sqrt(k);
for(int i = 1; i < S; ++i) inc(ans, f[k / i] * Query(i, i) % mod);
for (int l = S, r; l <= k; l = r + 1)
{
r = k / (k / l);
inc(ans, f[k / l] * Query(l, r) % mod);
}
write(ans);
putchar('\n');
}
return 0;
}
本文来自博客园,作者:蒟蒻orz,转载请注明原文链接:https://www.cnblogs.com/orzz/p/18122056