BZOJ4815: [Cqoi2017]小Q的表格

传送门

重点 1 1 1
f ( a , a + b ) a ( a + b ) = f ( a , b ) a b = f ( a , b − a ) a ( b − a ) = f ( a , b   m o d   a ) a ( b   m o d   a ) = f ( d , d ) d 2 \frac{f(a,a+b)}{a(a+b)}=\frac{f(a,b)}{ab}=\frac{f(a,b-a)}{a(b-a)}=\frac{f(a,b~mod~a)}{a(b~mod~a)}=\frac{f(d,d)}{d^2} a(a+b)f(a,a+b)=abf(a,b)=a(ba)f(a,ba)=a(b mod a)f(a,b mod a)=d2f(d,d)
其中 d = g c d ( a , b + b ) d=gcd(a,b+b) d=gcd(a,b+b)
那么
a n s = ∑ i = 1 k ∑ j = 1 k f ( i , j ) = ∑ i = 1 k ∑ j = 1 k ∑ d = 1 k [ g c d ( i , j ) = = d ] i j f ( d , d ) d 2 ans=\sum_{i=1}^{k}\sum_{j=1}^{k}f(i,j)=\sum_{i=1}^{k}\sum_{j=1}^{k}\sum_{d=1}^{k}[gcd(i,j)==d]\frac{ijf(d,d)}{d^2} ans=i=1kj=1kf(i,j)=i=1kj=1kd=1k[gcd(i,j)==d]d2ijf(d,d)
最终可以得到
a n s = ∑ d = 1 k f ( d , d ) ∑ i = 1 ⌊ k d ⌋ ∑ i = 1 ⌊ k d ⌋ [ i ⊥ j ] i j ans=\sum_{d=1}^{k}f(d,d)\sum_{i=1}^{\lfloor\frac{k}{d}\rfloor}\sum_{i=1}^{\lfloor\frac{k}{d}\rfloor}[i\perp j]ij ans=d=1kf(d,d)i=1dki=1dk[ij]ij
重点 2 2 2
考虑求
∑ i = 1 x ∑ j = 1 x [ i ⊥ j ] i j = 2 ∑ i = 1 x i ∑ j = 1 i [ i ⊥ j ] j − 1 \sum_{i=1}^{x}\sum_{j=1}^{x}[i\perp j]ij=2\sum_{i=1}^{x}i\sum_{j=1}^{i}[i\perp j]j-1 i=1xj=1x[ij]ij=2i=1xij=1i[ij]j1
除了 i = 1 i=1 i=1 以外,小于等于 i i i 的与 i i i 互质的数成对存在,那么这些数字的和就是 φ ( i ) i 2 \frac{\varphi(i)i}{2} 2φ(i)i
所以上面变成
∑ i = 1 x φ ( i ) i 2 \sum_{i=1}^{x}\varphi(i)i^2 i=1xφ(i)i2

a n s = ∑ d = 1 k f ( d , d ) ∑ i = 1 ⌊ k d ⌋ φ ( i ) i 2 ans=\sum_{d=1}^{k}f(d,d)\sum_{i=1}^{\lfloor\frac{k}{d}\rfloor}\varphi(i)i^2 ans=d=1kf(d,d)i=1dkφ(i)i2
筛出 ∑ i = 1 x φ ( i ) i 2 \sum_{i=1}^{x}\varphi(i)i^2 i=1xφ(i)i2
维护 f ( d , d ) f(d,d) f(d,d) 的前缀和即可
分块即可暴力树状数组就过了

# include 
using namespace std;
typedef long long ll;

const int mod(1e9 + 7);
const int maxn(4e6 + 5);

inline int Pow(ll x, int y) {
	register ll ret = 1;
	for (; y; y >>= 1, x = x * x % mod)
		if (y & 1) ret = ret * x % mod;
	return ret;
}

inline void Inc(int &x, int y) {
	x = x + y >= mod ? x + y - mod : x + y;
}

int n, m, f[maxn], pr[maxn / 10], tot, sum[maxn], ans, lst[maxn];
bitset <maxn> ispr;

inline int Gcd(int a, int b) {
	return !b ? a : Gcd(b, a % b);
}

inline void Add(int x, int v) {
	for (; x <= n; x += x & -x) Inc(sum[x], v);
}

inline int Query(int x) {
	register int ret = 0;
	for (; x; x ^= x & -x) Inc(ret, sum[x]);
	return ret;
}

int main() {
	register int i, j, a, b, k, cur, p, d;
	register ll x;
	scanf("%d%d", &m, &n), f[1] = 1, ispr[1] = 1;
	for (i = 2; i <= n; ++i) {
		if (!ispr[i]) pr[++tot] = i, f[i] = i - 1;
		for (j = 1; j <= tot && i * pr[j] <= n; ++j) {
			ispr[i * pr[j]] = 1;
			if (i % pr[j]) f[i * pr[j]] = f[i] * (pr[j] - 1);
			else {
				f[i * pr[j]] = f[i] * pr[j];
				break;
			}
		}
	}
	for (i = 1; i <= n; ++i) {
		lst[i] = (ll)i * i % mod, Add(i, lst[i]);
		f[i] = (ll)lst[i] * f[i] % mod, Inc(f[i], f[i - 1]);
	}
	while (m) {
		ans = 0, --m, scanf("%d%d%lld%d", &a, &b, &x, &k), x %= mod;
		d = Gcd(a, b), Add(d, mod - lst[d]);
		lst[d] = (ll)d * d % mod * x % mod * Pow((ll)a * b % mod, mod - 2) % mod;
		Add(d, lst[d]);
		for (p = 0, i = 1, j; i <= k; i = j + 1) {
			j = k / (k / i), cur = Query(j);
			Inc(ans, (ll)(cur - p + mod) * f[k / i] % mod), p = cur;
		}
		printf("%d\n", ans);
	}
    return 0;
}

你可能感兴趣的:(树状数组,反演与容斥)