P3700 [CQOI2017]小Q的表格

P3700 [CQOI2017]小Q的表格

有一个表格,满足:

f(a,b)=f(b,a)b×f(a,a+b)=(a+b)×f(a,b)\begin{aligned} &f(a,b)=f(b,a)\\ &b \times f(a,a+b)=(a+b)\times f(a,b) \end{aligned}

且一开始 f(a,b)=a×bf(a,b)=a\times b,然后带上一个单点修改操作。

每当修改了一个格子的数之后,为了让表格继续满足上述两个条件,你还需要把这次修改能够波及到的全部格子里都改为恰当的数。

你还需要随时输出前 kk 行前 kk 列这个有限区域内所有数的和 (mod109+7)\pmod {10^9+7}

考虑从下面那个式子得出一些可以反演的东西,有:

b×f(a,a+b)=(a+b)×f(a,b)ab×f(a,a+b)=a(a+b)×f(a,b)f(a,a+b)a(a+b)=f(a,b)abf(a,b)ab=f(gcd(a,b),gcd(a,b))gcd(a,b)2\begin{aligned} b \times f(a,a+b)&=(a+b)\times f(a,b)\\ ab \times f(a,a+b)&=a(a+b)\times f(a,b)\\ \frac{f(a,a+b)}{a(a+b)}&=\frac{f(a,b)}{ab}\\ \frac{f(a,b)}{ab}&=\frac{f(\gcd(a,b),\gcd(a,b))}{\gcd(a,b)^2} \end{aligned}

gcd(a,b)=d\gcd(a,b)=d,则有:

f(a,b)ab=f(d,d)d2f(a,b)=f(d,d)×abd2\begin{aligned} \frac{f(a,b)}{ab}&=\frac{f(d,d)}{d^2}\\ f(a,b)&=\frac{f(d,d)\times ab}{d^2} \end{aligned}

考虑到这个矩阵要变换,因为修改一个位置 (a,b)(a,b) 的值后有且仅有 gcd(x,y)=d\gcd(x,y)=d(x,y)(x,y) 位置的 ff 值会跟着变化,那么用一个树状数组维护 f(d,d)f(d,d) 即可。

f(d,d)=g(d)f(d,d)=g(d),再考虑答案:

ans=d=1ng(d)i=1nj=1nijgcd(i,j)2[gcd(i,j)=d]=d=1ng(d)i=1ndj=1ndij[gcd(i,j)=1]=d=1ng(d)i=1ndj=1ndijpgcd(i,j)μ(p)=d=1ng(d)p=1ndμ(p)i=1ndi[pi]j=1ndj[pj]=d=1ng(d)p=1ndμ(p)p2(i=1ndpi)2=d=1ng(d)p=1ndμ(p)p2S(ndp)2\begin{aligned} ans&=\sum_{d=1}^{n}g(d)\sum_{i=1}^{n}\sum_{j=1}^{n}\frac{ij}{\gcd(i,j)^2}[\gcd(i,j)=d]\\ &=\sum_{d=1}^{n}g(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}ij[\gcd(i,j)=1]\\ &=\sum_{d=1}^{n}g(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}ij\sum_{p|\gcd(i,j)}\mu(p)\\ &=\sum_{d=1}^{n}g(d)\sum_{p=1}^{\lfloor\frac{n}{d}\rfloor}\mu(p) \sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}i[p|i]\sum_{j=1}^{\lfloor\frac{n}{d}\rfloor}j[p|j]\\ &=\sum_{d=1}^{n}g(d)\sum_{p=1}^{\lfloor\frac{n}{d}\rfloor}\mu(p)p^2\left(\sum_{i=1}^{\lfloor\frac{\lfloor\frac{n}{d}\rfloor}{p}\rfloor}i\right)^2\\ &=\sum_{d=1}^{n}g(d)\sum_{p=1}^{\lfloor\frac{n}{d}\rfloor}\mu(p)p^2S(\lfloor\frac{\lfloor\frac{n}{d}\rfloor}{p}\rfloor) ^2 \end{aligned}

G(n)=i=1ni2μ(i)S(ni)2G(n)=\sum\limits_{i=1}^{n}i^2\mu(i)S(\lfloor\frac{n}{i}\rfloor)^2,则原式等于:

d=1ng(d)G(nd)\sum_{d=1}^{n}g(d)G(\lfloor\frac{n}{d}\rfloor)

根据 nin1i=[in]\lfloor\frac{n}{i}\rfloor-\lfloor\frac{n-1}{i}\rfloor=[i|n],有:

G(n)G(n1)=ini2μ(i)(S(ni)2S(ni1)2=ini2μ(i)(ni)3=n2inμ(i)ni=n2φ(n)\begin{aligned} G(n)-G(n-1)&=\sum_{i|n}i^2\mu(i)(S(\lfloor\frac{n}{i}\rfloor)^2-S(\lfloor\frac{n}{i}\rfloor-1)^2\\ &=\sum_{i|n}i^2\mu(i)(\frac{n}{i})^3\\ &=n^2\sum_{i|n}\mu(i)\frac{n}{i}\\ &=n^2\varphi(n) \end{aligned}

那么有:

G(n)=i=1ni2φ(i)G(n)=\sum_{i=1}^{n}i^2\varphi(i)

那么原式等于:

d=1ng(d)i=1ndi2φ(i)\sum_{d=1}^{n}g(d)\sum_{i=1}^{\lfloor\frac{n}{d}\rfloor}i^2\varphi(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;
}
posted @ 2022-01-13 11:53  蒟蒻orz  阅读(3)  评论(0编辑  收藏  举报  来源