异位坍缩 题解
littleKtian · · 题解
样例解释已经很明显告诉你先计算所有选择子串方案的概率和再除掉方案数了。
先考虑去掉
设
有递推式
或者写成
特别的,
观察如何给这个式子加上
注意到式子中的
因此我们修改
于是有
现在的问题是如何计算
(因为两者计算方法基本相同所以下面只讲一个)
假设我们现在要计算一个串有多少个串
有递推式
把递推式写成矩阵的形式,有:
因为两种情况使用的矩阵不同,我们不能直接进行矩阵快速幂。但我们发现在计算时用的都是一连串的矩阵,,并且头部和尾部都往一个方向移动。所以我们可以在计算时直接在尾部乘上一个新的矩阵,并在头部乘上一个逆矩阵,这样每次只需要做两次矩阵乘法就能直接得到新的用于计算的矩阵。从而计算出
上面两个矩阵的逆矩阵分别为
时间复杂度
#include<bits/stdc++.h>
#define p 998244353
using namespace std;
struct jx{
int a[2][2];
};
jx operator *(const jx &x,const jx &y)
{
jx z;
z.a[0][0]=(1ll*x.a[0][0]*y.a[0][0]+1ll*x.a[0][1]*y.a[1][0])%p;
z.a[1][0]=(1ll*x.a[1][0]*y.a[0][0]+1ll*x.a[1][1]*y.a[1][0])%p;
z.a[0][1]=(1ll*x.a[0][0]*y.a[0][1]+1ll*x.a[0][1]*y.a[1][1])%p;
z.a[1][1]=(1ll*x.a[1][0]*y.a[0][1]+1ll*x.a[1][1]*y.a[1][1])%p;
return z;
}
jx A[2],B[2],aa;
int n,l,r,a[5000005],fl[2][5000005],fr[2][5000005],f[2][5000005],ans,cho,pl,pr,p2;
int P(int x,int y=p-2)
{
int z=1;
for(;y;x=1ll*x*x%p,y>>=1)if(y&1)z=1ll*z*x%p;
return z;
}
int main()
{
A[0].a[0][0]=A[0].a[0][1]=A[0].a[1][0]=1,B[0].a[0][1]=B[0].a[1][0]=1,B[0].a[1][1]=p-1;
A[1].a[0][0]=A[1].a[1][0]=A[1].a[1][1]=1,B[1].a[0][0]=B[1].a[1][1]=1,B[1].a[1][0]=p-1;
scanf("%d%d%d",&n,&l,&r);
pl=P(P(2,l)),pr=P(P(2,r+1)),cho=P((1ll*(n*2-l-r+2)*(r-l+1)/2)%p),p2=P(2);
for(int i=1;i<=n;i++)
{
char ch=getchar();
while(ch!='0'&&ch!='1')ch=getchar();
a[i]=ch-'0';
}
aa.a[0][0]=aa.a[1][1]=1,aa.a[0][1]=aa.a[1][0]=0;
for(int i=1;i<l;i++)aa=aa*A[a[i]];
for(int i=l;i<=n;i++)
{
aa=B[a[i-l+1]]*aa*A[a[i]];
fl[0][i]=(aa.a[0][0]+aa.a[1][0])%p,fl[1][i]=(aa.a[0][1]+aa.a[1][1])%p;
}
aa.a[0][0]=aa.a[1][1]=1,aa.a[0][1]=aa.a[1][0]=0;
for(int i=1;i<=r;i++)aa=aa*A[a[i]];
for(int i=r+1;i<=n;i++)
{
aa=B[a[i-r]]*aa*A[a[i]];
fr[0][i]=(aa.a[0][0]+aa.a[1][0])%p,fr[1][i]=(aa.a[0][1]+aa.a[1][1])%p;
}
for(int i=1;i<=n;i++)f[0][i]=((1ll*p2*(f[0][i-1]+f[1][i-1])+1ll*pl*fl[0][i]-1ll*pr*fr[0][i])%p+p)%p,f[1][i]=((1ll*p2*f[a[i]][i-1]+1ll*pl*fl[1][i]-1ll*pr*fr[1][i])%p+p)%p;
for(int i=1;i<=n;i++)ans=(ans+(f[0][i]+f[1][i])%p)%p;
printf("%lld",1ll*ans*cho%p);
}