P5320 [BJOI2019]勘破神机
题目大意
设 \(f_i\) 为使用 \(1\times 2\) 的瓷砖覆盖 \(2*n\) 的地板的方案数, \(g_i\) 为使用 \(1\times 2\) 的瓷砖覆盖 \(3*n\) 的地板的方案数。给定 \(l,r,k\),求
\(1\leqslant l\leqslant r\leqslant 10^{18},1\leqslant k\leqslant 501\)。
解法
前置知识:特征根方程(也许不需要),下降幂转普通幂:
有关这方面的知识建议看混凝土数学系统学习,在此不做赘述。
首先考虑 \(m=2\) 的情况。
\(f_i\) 显然为 \(\text{fibonacci}_{i+1}\)。
看到 \(l\) 和 \(r\) 无比巨大的范围,就应该放弃递推公式。
人尽皆知的,斐波那契数列的通项公式为(接下来以 \(f_i\) 代替 \(\text{fibonacci}_{i}\)):
接下来开始推式子:
\(\color{blue}{(1)}:\) 下降幂转普通幂
\(\color{blue}{(2)}:\) 二项式定理
观察到 \(\sum\limits_{n=l}^r(\phi^{j}\hat\phi^{i-j})^n\) 是一个等比数列的形式可以直接算,再预处理一下 \(\frac{1}{\sqrt 5}\) 的幂就可以做到 \(O(k^2\log V)\) 了。
当然还有一个问题:\(\sqrt 5\) 在模 \(998244353\) 的情况下没有剩余系。
不过也是无关紧要的,只需要写一个 \(x+\sqrt 5y\) 的扩展系就行了,反正最后都会消掉。只是代码量会翻倍就是了
接下来考虑 \(m=3\)。
由于没有现成的通项公式,所以只能解特征根方程(不过 \(m=2\) 本来也是解特征根方程出来的)。先求出递推式:
显然当 \(i\) 为奇数时 \(g_i=0\),所以接下来的 \(g_i\) 默认为实际上的 \(g_{2i}\)
将地板分割成若干个 \(2\times3\) 的部分。
观察发现,如果有瓷砖覆盖到的边界,那么只能是这样的:

又由于如上图可以上下翻转,那么可以得出递推式:
\(g_i=3g_{i-1}+2\sum\limits_{j=0}^{i-2}g_j\)
再对相邻项做差,可以得到递推式:
\(g_i=4g_{i-1}-g_{i-2}\)
接下来就是手算的 Dirty work 了…
最后解出来的通项公式为 \(g_i=\frac{(2+\sqrt 3)^n}{3-\sqrt 3}+\frac{(2-\sqrt 3)^n}{3+\sqrt 3}\)
把前面 \(m=2\) 的扩展系改改,预处理的东西改一下就一样了。
接下来是一些提醒:
记得 \(m=2\) 时 \(l,r\) 要加一,\(m=3\) 时要除以 \(2\)。
等比数列记得有特判。
快速幂的指数不用取模。
最后是代码:
#include<bits/stdc++.h>
#define K 510
#define mod 998244353
#define ll long long
using namespace std;
ll s[K][K],c[K][K],fac[K],T,m,l,r,k,n,sqn;
ll qp(ll x,ll y)
{
	ll z=1;x%=mod;
	for(;y;y>>=1,x=x*x%mod)if(y&1)z=z*x%mod;
	return z;
}
struct qq{
	ll x,sqr;
	qq operator +(qq y){qq tmp;tmp.x=((x+y.x)%mod+mod)%mod;tmp.sqr=((sqr+y.sqr)%mod+mod)%mod;return tmp;}
	qq operator *(qq y){qq tmp;tmp.x=((x*y.x+sqn*sqr*y.sqr)%mod+mod)%mod;tmp.sqr=((sqr*y.x+x*y.sqr)%mod+mod)%mod;return tmp;}
	qq operator *(ll y){qq tmp;tmp.x=((x*y)%mod+mod)%mod;tmp.sqr=((sqr*y)%mod+mod)%mod;return tmp;}
	qq operator /(qq y)
	{
		qq tmp,z;
		ll den=qp(((y.x*y.x%mod-y.sqr*y.sqr%mod*sqn%mod+mod)%mod+mod)%mod,mod-2);
		tmp.x=(((x*y.x-sqn*sqr*y.sqr)%mod+mod)%mod*den%mod+mod)%mod;
		tmp.sqr=(((sqr*y.x-x*y.sqr)%mod+mod)%mod*den%mod+mod)%mod;
		return tmp;
	}
}a[K],b[K],phi,dphi;
qq make(ll x,ll y){qq tmp;tmp.x=(x%mod+mod)%mod;tmp.sqr=(y%mod+mod)%mod;return tmp;}
qq qp(qq x,ll y)
{
	qq z=make(1,0);
	for(;y;y>>=1,x=x*x)if(y&1)z=z*x;
	return z;
}
int main()
{
	cin>>T>>m;
	if(m==2){sqn=5;a[1]=make(1,0)/make(0,1);b[1]=make(1,0)/make(0,-1);phi=make(1,1)/make(2,0);dphi=make(1,-1)/make(2,0);}
	else{sqn=3;a[1]=make(1,0)/make(3,-1);b[1]=make(1,0)/make(3,1);phi=make(2,1);dphi=make(2,-1);}
	s[0][0]=c[0][0]=fac[0]=1;
	a[0]=b[0]=make(1,0);
	for(int i=1;i<=501;i++)
	{
		for(int j=0;j<=i;j++)
			s[i][j]=((i-1)*s[i-1][j]+s[i-1][j-1])%mod,c[i][j]=(c[i-1][j]+c[i-1][j-1])%mod;
		a[i]=a[i-1]*a[1];b[i]=b[i-1]*b[1];fac[i]=fac[i-1]*i%mod;
	}
	while(T--)
	{
		cin>>l>>r>>k;
		n=r-l+1;
		if(m==2)l++,r++;
		if(m==3)l=(l+1)/2,r/=2;
		qq sum=make(0,0);
		for(int i=0;i<=k;i++)
		{
			qq tmp=make(0,0);
			for(int j=0;j<=i;j++)
			{
				qq qwq=qp(phi,j)*qp(dphi,i-j);
				tmp=tmp+(a[j]*b[i-j]*c[i][j]*(qwq.x==1&&qwq.sqr==0?make(r-l+1,0):(qp(qwq,l)*(qp(qwq,r-l+1)+make(-1,0))/(qwq+make(-1,0)))));
			}
			sum=sum+(tmp*s[k][i]*((k-i)&1?-1:1));
		}
		sum=sum*qp(n,mod-2)*qp(fac[k],mod-2);
		cout<<sum.x<<'\n';
	}
}

                
            
        
浙公网安备 33010602011771号