P3700 [CQOI2017]小Q的表格

题目链接

容易看出,

\[\frac{f(a,b)}{ab} = \frac{f(g,g)}{gg} \]

转化为维护 \(f(g,g)\)。现在我们要求和:

\[\sum_{i<=K,j<=K}f(i,j) \]

\[=\sum_{g=1}^Kf(g)\sum_{i,j<=K/g}ij[(i,j)=1] \]

然后我们需要一个技巧

\[\large \sum_{i=1}^xi[(i,x)=1]=\frac{x(\varphi(x)+\epsilon(x))}{2} \]

感性地理解一下。显然,如果 \((x,i)=1\),那么必定有 \((x-i,i)=1\),因此和 \(x\) 互质的数是“对称的”。不过 \(x=1\) 比较特殊,它等于1.

然后剩下的就简单了:

\[G(x)=\sum_{i,j<=K/g}ij[(i,j)=1]=\sum_{i=1}^xi^2\varphi(i) \]

这个直接预处理。

\[\sum_{g=1}^Kf(g)G(\left \lfloor \frac{K}{g} \right \rfloor ) \]

这个整除分块。不过我们需要 \(O(1)\) 算出一个 \(f\) 的前缀和。这个分块维护一下前缀和即可。

关键代码:

int m, n;
ll f[N], sum[N], G[N];
int block, blong[N], st[NN], ed[NN], tag[NN];
int pri[N], pcnt, phi[N];
bool depri[N];
inline void init() {
	for (register int i = 1; i <= n; ++i)	G[i] = (G[i - 1] + 1ll * i * i % P * phi[i]) % P;
	for (register int i = 1; i <= n; ++i)
		f[i] = 1ll * i * i % P, sum[i] = (f[i] + sum[i - 1]) % P;
}
inline void modify(int p, int x) {
	int tmp = x;//Attention!!!!!
	x = x - f[p];
	f[p] = tmp;
	for (register int i = p; i <= ed[blong[p]]; ++i)	ADD(sum[i], x);
	for (register int i = blong[p] + 1; i <= blong[n]; ++i)	ADD(tag[i], x);
}
inline ll get_sum(int p) {
	return sum[p] + tag[blong[p]];
}
inline void query(int K) {
	ll res = 0;
	for (register int l = 1, r; l <= K; l = r + 1) {
		r = (K / (K / l));
		res = (res + (get_sum(r) - get_sum(l - 1)) * G[K / l]) % P;
	}
	printf("%lld\n", (res % P + P) % P);
}
inline void work() {
	for (register int i = 1; i <= m; ++i) {
		int a, b, x, k; read(a), read(b), read(x), read(k);
		int g = get_gcd(a, b);
		x %= P;//Attention!!!!!!!!!
		modify(g, 1ll * x * g % P * g  % P * quickpow(a, P - 2) % P * quickpow(b, P - 2) % P);
		query(k);
	}
}
posted @ 2020-08-09 11:00  JiaZP  阅读(114)  评论(0编辑  收藏  举报