P8956题解
ztntonny
·
·
题解
前言:本题解 \LaTeX 使用较多,如果渲染失败请移步与此。
题意
非常喜欢这道题,考察到了多方面的知识以及非常坑的取模,下面简述一下:
给定 5 个整数 n,A,B,X,Y,求对于两串串数列:
\begin{aligned}
F_{A,B}(1)=A,F_{A,B}(2)=B,F_{A,B}(x)=\lfloor \sqrt{F_{A,B}(x-2)F_{A,B}(x-1)}\rfloor+1\;(x \ge 3)\\
F_{X,Y}(1)=X,F_{X,Y}(2)=Y,F_{X,Y}(x)=\lfloor \sqrt{F_{X,Y}(x-2)F_{X,Y}(x-1)}\rfloor+1\;(x \ge 3)
\end{aligned}
\right.
的:
\prod_{i=1}^nF_{X,Y}(i)-F_{A,B}(i)
思路
首先,意识到 \sqrt{F(x-2)F(x-1)}+1 就是 F(x-2),F(x-1) 的几何平均值加上一,且由均值不等式得到
\sqrt{F(x-2)F(x-1)}+1\leq \frac{F(x-2)+F(x-1)}{2}+1
所以得出,数列 F 一定有 F(x)=F(x+1) 且满足 x\leq\log{(F(1)\times F(2))}+1(记 x_{F_{A,B}},x_{F_{X,Y}} 分别为 F_{x,y},F_{A,B} 的第一项满足 F(x)=F(x+1) 的下标)。
那么就不难得到,在 F(x+1) 之后数列形状:
F(x+2)=F(x)+1,F(x+3)=F(x)+1,F(x+4)=F(x)+2,F(x+5)=F(x)+2\ldots
即:
F(x+n)=F(x)+\lfloor\frac{n}{2}\rfloor
那么实际上我们已经可以用 \mathcal{O}(\log{(X\times Y)}) 的时间复杂度求出 F_{X,Y},用 \mathcal{O}(\log {A\times B}) 的时间复杂度求出 F_{A,B} 了。下面分析 \prod_{i=1}^nF_{X,Y}(i)-F_{A,B}(i):
此式子若 n\leq \min(x_{F_{A,B}},x_{F_{X,Y}}) 还可以暴力计算,时间复杂度 \mathcal{O}(\min(\log{(A\times B)},\log{(X\times Y)})),但是若 n 已经取到 10^9 级别,就需要考虑更快的方法了,我们推导在 \max(x_{F_{A,B}},x_{F_{X,Y}}) 以后的乘积形式:
(F_{A,B}(x)-F_{X,Y}(x))\times(F_{A,B}(x+1)-F_{X,Y}(x+1))\times\ldots
考虑 F_{A,B}(n)=F_{A,B}(x)+\lfloor\frac{n-x}{2}\rfloor,简化成为:
(F_{A,B}(x_{F_{A,B}})+\lfloor\frac{x-x_{F_{A,B}}}{2}\rfloor-F_{X,Y}(x_{F_{X,Y}})+\lfloor\frac{x-x_{F_{X,Y}}}{2}\rfloor)\times(F_{A,B}(x_{F_{A,B}})+\lfloor\frac{x+1-x_{F_{A,B}}}{2}\rfloor-F_{X,Y}(x_{F_{X,Y}})+\lfloor\frac{x+1-x_{F_{X,Y}}}{2}\rfloor)\times\ldots
易得第 x 项:
F_{A,B}(x_{F_{A,B}})+\lfloor\frac{x-x_{F_{A,B}}}{2}\rfloor-F_{X,Y}(x_{F_{X,Y}})+\lfloor\frac{x-x_{F_{X,Y}}}{2}\rfloor
不难发现,当 x_{F_{A,B}}\mod 2\equiv x_{F_{X,Y}}\mod 2 时:
F_{A,B}(x_{F_{A,B}})+\lfloor\frac{x-x_{F_{A,B}}}{2}\rfloor-F_{X,Y}(x_{F_{X,Y}})+\lfloor\frac{x-x_{F_{X,Y}}}{2}\rfloor= F_{A,B}(x_{F_{A,B}})-F_{X,Y}(x_{F_{X,Y}})
那么原式实际上就成为了:
(F_{A,B}(x_{F_{A,B}})-F_{X,Y}(x_{F_{X,Y}}))^{n-\max(x_{F_{A,B}},x_{F_{X,Y}})+1}
肉眼可见可以使用快速幂解决。
那么当 x_{F_{A,B}}\mod 2\not\equiv x_{F_{X,Y}}\mod 2 时:
(F_{A,B}(x_{F_{A,B}})+\lfloor\frac{x-x_{F_{A,B}}}{2}\rfloor-F_{X,Y}(x_{F_{X,Y}})+\lfloor\frac{x-x_{F_{X,Y}}}{2}\rfloor)\times(F_{A,B}(x_{F_{A,B}})+\lfloor\frac{x+1-x_{F_{A,B}}}{2}\rfloor-F_{X,Y}(x_{F_{X,Y}})+\lfloor\frac{x+1-x_{F_{X,Y}}}{2}\rfloor)=(F_{A,B}(x_{F_{A,B}})-F_{X,Y}(x_{F_{X,Y}}))\times(F_{A,B}(x_{F_{A,B}}+1)-F_{X,Y}(x_{F_{X,Y}}+1))
原式实际上成为:
(F_{A,B}(x_{F_{A,B}})-F_{X,Y}(x_{F_{X,Y}}))\times(F_{A,B}(x_{F_{A,B}}+1)-F_{X,Y}(x_{F_{X,Y}}+1))^{\lfloor\frac{n-\max(x_{F_{A,B}},x_{F_{X,Y}})+1}{2}\rfloor}\times (F_{A,B}(x_{F_{A,B}})-F_{X,Y}(x_{F_{X,Y}}))^{(n-\max(x_{F_{A,B}},x_{F_{X,Y}})+1)\mod 2}
同样可以使用快速幂解决。
那么这样,实际上整个程序的时间复杂度就是 \mathcal{O}(t\log n) 级别的了,完结撒代码:
#include <bits/stdc++.h>
#define ll long long
using namespace std;
const ll MOD = 998244353;
ll t , n , a , b , x , y , cmp1 , cmp2;
long double f[105] , g[105];
ll fpow( ll xx , ll yy )
{
if ( yy == 0 ) return 1;
ll z = fpow( xx , yy / 2 ) % MOD;
if ( yy % 2 ) return ( ( z * z ) % MOD * xx ) % MOD;
else return ( z * z ) % MOD;
}
ll ff( ll xx )
{
if ( xx > cmp1 ) return ( ( ( xx - cmp1 ) / 2 ) % MOD + (ll)f[cmp1] ) % MOD;
else return (ll)f[xx];
}
ll gg( ll xx )
{
if ( xx > cmp2 ) return ( ( ( xx - cmp2 ) / 2 ) % MOD + (ll)g[cmp2] ) % MOD;
else return (ll)g[xx];
}
int main()
{
cin >> t;
for ( ll k = 1; k <= t; k++ )
{
ll cmp , ans = 1;
cmp1 = 2 , cmp2 = 2 , cin >> n >> a >> b >> x >> y , f[1] = a , f[2] = b , g[1] = x , g[2] = y;
while ( f[++cmp1 - 1] != f[cmp1 - 2] && cmp1 <= n + 3 ) f[cmp1] = ( (ll)( sqrt( f[cmp1 - 1] * f[cmp1 - 2] ) ) + 1 ) % MOD;
while ( g[++cmp2 - 1] != g[cmp2 - 2] && cmp2 <= n + 3 ) g[cmp2] = ( (ll)( sqrt( g[cmp2 - 1] * g[cmp2 - 2] ) ) + 1 ) % MOD;
cmp1 -= 2 , cmp2 -= 2 , cmp = max( cmp1 , cmp2 );
for ( ll i = 1; i <= min( n , cmp - 1 ); i++ ) ans *= ( gg( i ) - ff( i ) ) % MOD , ans %= MOD;
if ( cmp <= n )
{
if ( cmp1 % 2 == cmp2 % 2 ) ans *= fpow( ( gg( cmp ) - ff( cmp ) ) % MOD , n - cmp + 1 ) , ans %= MOD;
else
{
ans *= fpow( ( ( gg( cmp ) - ff( cmp ) ) % MOD * ( gg( cmp + 1 ) - ff( cmp + 1 ) ) % MOD ) % MOD , ( n - cmp + 1 ) / 2 ) , ans %= MOD;
if ( ( n - cmp + 1 ) % 2 ) ans *= ( gg( cmp ) - ff( cmp ) ) % MOD , ans %= MOD;
}
}
cout << ( ans + MOD ) % MOD << endl;
}
return 0;
}