有一个表格,满足:
f(a,b)=f(b,a)b×f(a,a+b)=(a+b)×f(a,b)
且一开始 f(a,b)=a×b,然后带上一个单点修改操作。
每当修改了一个格子的数之后,为了让表格继续满足上述两个条件,你还需要把这次修改能够波及到的全部格子里都改为恰当的数。
你还需要随时输出前 k 行前 k 列这个有限区域内所有数的和 (mod109+7)。
考虑从下面那个式子得出一些可以反演的东西,有:
b×f(a,a+b)ab×f(a,a+b)a(a+b)f(a,a+b)abf(a,b)=(a+b)×f(a,b)=a(a+b)×f(a,b)=abf(a,b)=gcd(a,b)2f(gcd(a,b),gcd(a,b))
设 gcd(a,b)=d,则有:
abf(a,b)f(a,b)=d2f(d,d)=d2f(d,d)×ab
考虑到这个矩阵要变换,因为修改一个位置 (a,b) 的值后有且仅有 gcd(x,y)=d 的 (x,y) 位置的 f 值会跟着变化,那么用一个树状数组维护 f(d,d) 即可。
设 f(d,d)=g(d),再考虑答案:
ans=d=1∑ng(d)i=1∑nj=1∑ngcd(i,j)2ij[gcd(i,j)=d]=d=1∑ng(d)i=1∑⌊dn⌋j=1∑⌊dn⌋ij[gcd(i,j)=1]=d=1∑ng(d)i=1∑⌊dn⌋j=1∑⌊dn⌋ijp∣gcd(i,j)∑μ(p)=d=1∑ng(d)p=1∑⌊dn⌋μ(p)i=1∑⌊dn⌋i[p∣i]j=1∑⌊dn⌋j[p∣j]=d=1∑ng(d)p=1∑⌊dn⌋μ(p)p2i=1∑⌊p⌊dn⌋⌋i2=d=1∑ng(d)p=1∑⌊dn⌋μ(p)p2S(⌊p⌊dn⌋⌋)2
设 G(n)=i=1∑ni2μ(i)S(⌊in⌋)2,则原式等于:
d=1∑ng(d)G(⌊dn⌋)
根据 ⌊in⌋−⌊in−1⌋=[i∣n],有:
G(n)−G(n−1)=i∣n∑i2μ(i)(S(⌊in⌋)2−S(⌊in⌋−1)2=i∣n∑i2μ(i)(in)3=n2i∣n∑μ(i)in=n2φ(n)
那么有:
G(n)=i=1∑ni2φ(i)
那么原式等于:
d=1∑ng(d)i=1∑⌊dn⌋i2φ(i)
线性筛,维护前缀和,再数论分块即可。
#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;
}