[MtOI2019]幽灵军团
题意
求下面表达式的值,
其中,\(type=\{0,1,2\}\),\(f(type)\)满足:
其中, \(A,B,C \leqslant 10^5.\)
Solution
type = 0
拿到这个式子非常兴奋,然后就开始疯狂化简,最终化简成了一个\(O(n\sqrt{n} \log {n})\)的表达式,非常沮丧的是不能满足题目的要求。
我们重新分析这个式子,
不难发现,这个式子的\(i,j,k\)是对称的,相当于我们仅需要计算以下两部分式子的值,然后将其组合起来,
分别来对两个式子进行化简
可以通过预处理前缀积\(O(\log{n})\)实现对于此式的计算。
接下来只计算其本身的值,然后再计算逆元求出答案。
跟[SDOI2017]数字表格类似的,则有,
里面的部分在上述题目中已经处理过了,只需要计算最终得到值的\(C\)次幂,便可以计算出此答案。
type = 1
大致的思路显然跟上面类似,重新推一遍两个式子即可。
记\(S(n) = \sum_{i=1}^{n} i = \frac{n \times (n + 1)}{2}\),则有,
与\(type=0\)类似的,我们可以通过预处理 \(i^i\)的前缀积,然后可以在\(O(\log{n})\)的时间复杂度内求解这一部分的值。
记\(T=xd\),则有,
类似\(type=0\),不难发现 \(\prod_{d|T} d ^ {d^2 \mu(\frac{T}{d})}\) 可以枚举因子进行计算,在 \(O(n\sqrt{n})\) 的时间复杂度下完成预处理。
然后对\(T\)进行数论分块,可以在 \(O(\log{n} \sqrt{n}\) 下完成整个式子的计算。
type = 2
ln大法好
特别感谢洛谷题解区peterwuyihong的idea。
对于比较复杂的指数问题,我们可以想到将其进行\(ln\)和\(exp\)操作。
对他取\(ln\)操作:
莫比乌斯经典枚举因子,则有,
记\(T=xd\),则有
然后将其\(exp\)一下,得到结果,
然后可以调用\(type=1\)的结果,就可以完成计算。
官方题解
与上面类似,我们分别对两个式子化简。
记\(T=xd\),则有,
分离内层的\(i \times T\),则有
可以发现通过对内部函数\(O(n\sqrt{n}\log{n})\)的预处理,可以在\(O(\sqrt{n}\log{n})\)的时间复杂度内数论分块求解,但是先不着急求解,我们可以先计算下一个表达式。
枚举情况更为复杂的\(gcd(i,j,k)\),
(请允许我跳过一些步骤qwq)
与上面类似,可以尝试分离\(xd\)和\(gcd(i,j)\)
对于\(xd\)分离出的部分,我们记\(T=xd\),化简则有,
发现这一部分恰好为上一个式子所处理出的结果的一部分,又因为这一部分作为分母计入答案,所以说上下完全可以消掉,不再需要计算这一部分。
这个结论是将\(\prod \prod \prod i^{f(2)}\)和\(\prod \prod \prod gcd(i,j)^{f(2)}\)组合,但是实际中还有\(k\)的加入,其实可以通过将\(j\)和\(gcd(i,j)\)组合,将\(i\)与\(gcd(i,k)\)组合,就可以完美的使用两次这个结论。
接下来化简第二个式子中剩余的部分。
取出其中的部分式子,
这个式子是经典的,化简过程略。
代回原表达式,记\(T=xd, T'=x'd'\),化简则有(上标略),
最里面的部分在\(type=0\)时已经处理过了,外层的两个循环使用两次数论分块即可,时间复杂度\(O(n^{\frac{3}{4}} \log{n}).\)
最后将第一个式子剩余部分乘上第二个式子剩余部分的逆元,即可求出答案的值。
卡常
在计算的过程中,会发现诸多预处理的变量中,有大量的需要求解其逆元,并且若干\(\sum_{i=1}^n i\)或者\(\prod_{i=1}^n i\)需要计算,可以通过预先处理其值,然后在后面的计算中直接调用,可以有效地提高程序的运行效率。
Code
点击查看代码
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
const int N = 1e6 + 50;
inline int min(register int a, register int b) {
	return (a < b ? a : b);
}
inline int read() {
	register int res = 0, f = 1;
	register char c = getchar();
	while (c > '9' || c < '0') {
		if (c == '-')  f = -1;
		c = getchar();
	}
	while (c >= '0' && c <= '9') {
		res = (res << 3) + (res << 1) + c - '0';
		c = getchar();
	}	
	return res * f;
}
int mod;
inline int add_mod(register int a, register int b) {
	a += b;
	if (a < 0)  a += mod;
	if (a >= mod)  a -= mod;
	return a;
}
inline int del_mod(register int a, register int b) {
	a -= b;
	if (a < 0)  a += mod;
	if (a >= mod)  a -= mod;
	return a;
}
inline int mul_mod(register int a, register int b) {
	a = 1ll * a * b % mod;
	return a;
}
int num;
int prime[N], mu[N];
int v[N];
int mul[N], pmul[N];
int g[N], invg[N];
int F[N], inv[N], G[N];
int S[N];
int invF[N], invG[N];
int phi[N], sumphi[N];
inline int qpow(register int a, register int b) {
	register int base = 1;
	while (b) {
		if (b & 1)  base = mul_mod(base, a);
		a = mul_mod(a, a);
		b >>= 1;
	}
	return base;
}
inline void init() {
	register int MAX = 1e5;
	F[0] = F[1] = mu[1] = 1;
	inv[0] = inv[1] = 1;
	pmul[1] = mul[1] = 1;
	g[1] = G[0] = G[1] = 1;
	invg[0] = invg[1] = 1;
	phi[1] = 1;
	S[1] = 1;
	for (register int i = 2; i <= MAX; ++i) {
		S[i] = (1ll * i * (i + 1) / 2) % (mod - 1);
		F[i] = G[i] = 1;
		invF[0] = invF[1] = invG[0] = invG[1] = 1;
		mul[i] = mul_mod(mul[i - 1], i);
		pmul[i] = mul_mod(pmul[i - 1], qpow(i, i));
		g[i] = i;
		invg[i] = qpow(g[i], mod - 2);
		inv[i] = qpow(i, mod - 2);
		if (!v[i]) {
			prime[++num] = i;
			v[i] = i;
			mu[i] = -1;
			phi[i] = i - 1;
		}
		for (register int j = 1; j <= num; ++j) {
			if (prime[j] > v[i] || prime[j] > MAX / i)  break;
			v[i * prime[j]] = prime[j];
			if (i % prime[j] == 0) {
				phi[i * prime[j]] = phi[i] * prime[j];
				mu[i * prime[j]] = 0;
				break;
			}
			phi[i * prime[j]] = phi[i] * phi[prime[j]];
			mu[i * prime[j]] = -mu[i];
		}
	}
	for (register int i = 1; i <= MAX; ++i) {
		sumphi[i] = (sumphi[i - 1] + phi[i]) % (mod - 1);
		if (!mu[i])   continue;
		for (register int j = i; j <= MAX; j += i) {
			F[j] = mul_mod(F[j], (mu[i] == 1 ? j / i : inv[j / i]));
			G[j] = mul_mod(G[j], qpow((mu[i] == 1 ? g[j / i] : invg[j / i]), (1ll * j * j % (mod - 1))));
		}
	}
	for (register int i = 2; i <= MAX; ++i) {
		F[i] = mul_mod(F[i], F[i - 1]);
		G[i] = mul_mod(G[i], G[i - 1]);
		invF[i] = qpow(F[i], mod - 2);
		invG[i] = qpow(G[i], mod - 2);
	}
}
inline int calc1(register int A, register int B, register int C) {
	register int res = qpow(mul[A], (1ll * B * C % (mod - 1)));
	res = mul_mod(res, qpow(mul[B], (1ll * A * C % (mod - 1))));
	register int tmp = 1;
	for (register int i = 1, j; i <= min(A, B); i = j + 1) {
		j = min(A / (A / i), B / (B / i));
		tmp = mul_mod(tmp, qpow(mul_mod(F[j], invF[i - 1]), (1ll * (A / i) * (B / i) % (mod - 1))));
	}
	tmp = qpow(tmp, C);
	res = mul_mod(res, qpow(tmp, mod - 2));
	tmp = 1;
	for (register int i = 1, j; i <= min(A, C); i = j + 1) {
		j = min(A / (A / i), C / (C / i));
		tmp = mul_mod(tmp, qpow(mul_mod(F[j], invF[i - 1]), (1ll * (A / i) * (C / i) % (mod - 1))));
	}
	tmp = qpow(tmp, B);
	res = mul_mod(res, qpow(tmp, mod - 2));
	return res;
}
inline int calc2(register int A, register int B, register int C) {
	register int res = qpow(pmul[A], 1ll * S[B] * S[C] % (mod - 1));
	res = mul_mod(res, qpow(pmul[B], 1ll * S[A] * S[C] % (mod - 1)));
	register int tmp = 1;
	for (register int i = 1, j; i <= min(A, B); i = j + 1) {
		j = min(A / (A / i), B / (B / i));
		tmp = mul_mod(tmp, qpow(mul_mod(G[j], invG[i - 1]), (1ll * S[A / i] * S[B / i] % (mod - 1))));
	}
	tmp = qpow(tmp, S[C]);
	res = mul_mod(res, qpow(tmp, mod - 2));
	tmp = 1;
	for (register int i = 1, j; i <= min(A, C); i = j + 1) {
		j = min(A / (A / i), C / (C / i));
		tmp = mul_mod(tmp, qpow(mul_mod(G[j], invG[i - 1]), (1ll * S[A / i] * S[C / i] % (mod - 1))));
	}
	tmp = qpow(tmp, S[B]);
	res = mul_mod(res, qpow(tmp, mod - 2));
	return res;
}
inline int SUM(register int A, register int B) {
	register int res = 1;
	for (register int i = 1, j; i <= min(A, B); i = j + 1) {
		j = min(A / (A / i), B / (B / i));
		res = mul_mod(res, qpow(mul_mod(F[j],invF[i - 1]), 1ll * (A / i) * (B / i) % (mod - 1)));
	}
	return res;
}
inline int calc3(register int A, register int B, register int C) {
	register int res = 1;
	for (register int i = 1, j; i <= min(min(A, B), C); i = j + 1) {
		j = min(min(A / (A / i), B / (B / i)), C / (C / i));
		res = mul_mod(res, qpow(mul[B / i], 1ll * (0ll + sumphi[j] - sumphi[i - 1] + (mod - 1)) * (A / i) % (mod - 1) * (C / i) % (mod - 1)));
	}
	int tmp = 1;
	for (register int i = 1, j; i <= min(B, min(A, C)); i = j + 1) {
		j = min(min(B / (B / i), A / (A / i)), C / (C / i));
		tmp = mul_mod(tmp, qpow(SUM(B / i, A / i), 1ll * (0ll + sumphi[j] - sumphi[i - 1] + (mod - 1)) * (C / i) % (mod - 1)));
	}
	res = mul_mod(res, qpow(tmp, mod - 2));
	for (register int i = 1, j; i <= min(min(A, B), C); i = j + 1) {
		j = min(min(A / (A / i), B / (B / i)), C / (C / i));
		res = mul_mod(res, qpow(mul[A / i], 1ll * (0ll + sumphi[j] -  sumphi[i - 1] + (mod - 1)) * (C / i) % (mod - 1) * (B / i) % (mod - 1)));
	}
	tmp = 1;
	for (register int i = 1, j; i <= min(B, min(A, C)); i = j + 1) {
		j = min(min(B / (B / i), A / (A / i)), C / (C / i));
		tmp = mul_mod(tmp, qpow(SUM(A / i, C / i), 1ll * (0ll + sumphi[j] - sumphi[i - 1] + (mod - 1)) * (B / i) % (mod - 1)));
	}
	res = mul_mod(res, qpow(tmp, mod - 2));
	return res;
}
int main () {
	register int T = read(); mod = read();
	init();
	register int A, B, C;
	while (T--) {
		A = read(), B = read(), C = read();
		printf("%d %d %d\n", calc1(A, B, C), calc2(A, B, C), calc3(A, B, C));
	}
    return 0;
}
顺便贴一下ln大法的代码实现:
点击查看代码
inline int calc2(register int A, register int B, register int C) {
	int res = 1;
	for (int i = 1, j; i <= min(min(A, B), C); i = j + 1) {
		j = min(min(A / (A / i), B / (B / i)), C / (C / i));
		res = mul_mod(res, qpow(calc0(A / i, B / i, C / i), (0ll + sumphi[j] - sumphi[i - 1] + (mod - 1)) % (mod - 1)));
	}
	return res;
}
后记
这个题的数学公式也太复杂了...
不得不把公式字体放大,然后又显得太蠢了...
然后卡常吧...
莫比乌斯反演《基础》练习题

 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号