CF1182E 名字太长不想打 题解
题解区都是用矩阵直接算封闭形式中 \(f_1,f_2,f_3\) 的系数的,这里给个更偏 MO 风格且好写的做法。
首先先想办法用 \(f_x \cdot k(x)\) 代 \(f_x\) 以消掉 \(c^{2x-6}\) 这个不好处理的东西。
明显 \(k(x)\) 是 \(c^{ax+b}\) 的形式,代进去对比系数可以发现 \(a=1,b=0\)。
于是 \(f_x \cdot c^{x} = (f_{x-1}\cdot c^{x-1}) (f_{x-2}\cdot c^{x-2})(f_{x-3}\cdot c^{x-3})\),这是一个很好看的形式。
做个换元,\(h_x=f_x \cdot c^{x}\),\(h\) 的前三项可以以 \(f\) 算出。
我们知道取个 \(\ln\) 就是标准矩乘形式,但是显然没必要。在矩乘中用乘方代替乘号,用乘法代替加法,就可以直接做这种东西了。事实上就是取个指数后的普通矩乘。
换句话说,我们的矩阵上递推的是指数。
这样能大大减少代码量,至于速度,我还没试(
由于我的矩阵用的是模板,代码达到了 2k
,然而核心部分非常短。
随便写不卡常就有 45ms
,轻松跑进第一页,吊打那些上百毫秒的每一项单独递推。
核心部分长这个样:
signed main(){
scanf("%lld %lld %lld %lld %lld", &n, &f1, &f2, &f3, &c);
int h0 = 1ll * f3 * qpow(c, 3) % mod,
h1 = 1ll * f2 * qpow(c, 2) % mod,
h2 = 1ll * f1 * qpow(c, 1) % mod;
matrix tran(3, 3);
tran[0][0] = tran[0][1] = tran[1][0] = tran[1][2] = tran[2][0] = 1;
tran = tran ^ (n-1);
int ans = 1ll * qpow(h0, tran[0][2]) * qpow(h1, tran[1][2]) % mod
* qpow(h2, tran[2][2]) % mod;
ans = 1ll * ans * qpow(inv(c), n % phi) % mod;
printf("%lld\n", ans);
}
完整代码见 此,也只是多一些矩阵板子和快速幂板子。
注意因为矩阵递推的是指数,矩阵运算时要膜 \(\varphi(mod) = mod-1\)。
这道题的十几篇题解几乎都是又慢又难写的每项分开矩乘,唯一的一篇与我的思路相同的还是靠灵感发现能够做此变换,实在令人感慨。
本文来自博客园,作者:purplevine,转载请注明原文链接:https://www.cnblogs.com/purplevine/p/16739781.html