P12602 指鹿为马 题解
下文为了区分,用
首先对于打出的东西,我们只关心其某一个后缀是否是
令
并且我们有
同时我们也就有
答案即为
这个东西虽然也能高斯消元,但是时间爆完了。
考虑一下,我们之所以做高斯消元,是因为不能只从之前的状态转移过来。然而发现
但是我们现在是知道的大的要反推小的。归纳一下的话,可以得到,对于任意的
#include<bits/stdc++.h>
#define N 300005
#define M 65
#define V 62
#define ll long long
#define mod 998244353
using namespace std;
ll qpow(ll x,ll y)
{
ll res=1;
x%=mod;
while(y)
{
if(y&1) res=res*x%mod;
x=x*x%mod;
y>>=1;
}
return res;
}
struct gaus{
ll a[M][M];
int n,m;
ll* operator[](int i){return a[i];}
void init(int x,int y){n=x,m=y;}
auto gauss()
{
for(int j=1;j<m;j++)
{
ll inv=qpow(a[j][j],mod-2);
for(int i=1;i<=n;i++)
{
if(i==j) continue;
ll t=a[i][j]*inv%mod;
for(int k=1;k<=m;k++) a[i][k]=(a[i][k]-t*a[j][k]%mod+mod)%mod;
}
}
vector<int>vec;
for(int i=1;i<=n;i++) vec.push_back(a[i][m]*qpow(a[i][i],mod-2)%mod);
return vec;
}
}equ;
struct info{
ll k,b;
}f[N];
int n,a[N],cnt1[M],cnt2[M][M],nxt[N][M],bd[N];
ll invc[M],g[N];
void border()
{
for(int i=2;i<=n;i++)
{
int j=bd[i-1];
while(j&&a[i]!=a[j+1]) j=bd[j];
bd[i]=j+(a[i]==a[j+1]);
}
for(int j=1;j<=V;j++)
{
for(int i=0;i<n;i++)
{
nxt[i][j]=(a[i+1]==j?i+1:nxt[bd[i]][j]);
}
}
}
int main()
{
//freopen("typewriter.in","r",stdin);
//freopen("typewriter.out","w",stdout);
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
string s;
cin>>s;
n=s.size();
for(int i=0;i<n;i++) a[i+1]=s[i]-(isdigit(s[i])?47:isupper(s[i])?54:60);
for(int i=1;i<=n;i++) cnt1[a[i]]++,cnt2[a[i]][a[i%n+1]]++;
border();
equ.init(V,V+1);
for(int i=1;i<=V;i++)
{
equ[i][i]=equ[i][V+1]=mod-1;
invc[i]=qpow(cnt1[i],mod-2);
// cerr<<invc[i]<<' ';
for(int j=1;j<=V;j++) (equ[i][j]+=cnt2[i][j]*invc[i]%mod)%=mod;
}
fill(equ[a[1]]+1,equ[a[1]]+V+2,0);
equ[a[1]][a[1]]=1;
// for(int i=1;i<=V;i++){for(int j=1;j<=V+1;j++)cerr<<equ[i][j]<<' ';cerr<<'\n';}
// cerr<<'\n';
auto vec=equ.gauss();
for(int i=1;i<=V;i++) g[i]=vec[i-1];//,cerr<<g[i]<<' ';cerr<<'\n';
f[1]={1,0};
for(int i=2;i<=n;i++)
{
ll inv=invc[a[i-1]];
f[i].k=f[i-1].k;
f[i].b=(f[i-1].b-cnt2[a[i-1]][a[i]]*inv%mod+mod)%mod;
for(int j=1;j<=V;j++)
{
ll p=cnt2[a[i-1]][j]*inv%mod;
if(nxt[i-1][j]==i) continue;
if(!nxt[i-1][j])
{
(f[i].k+=(mod-f[1].k)*p%mod)%=mod;
(f[i].b+=(mod-f[1].b-1-g[j])*p%mod+mod)%=mod;
continue;
}
(f[i].k+=(mod-f[nxt[i-1][j]].k)*p%mod)%=mod;
(f[i].b+=(mod-f[nxt[i-1][j]].b-1)*p%mod)%=mod;
}
ll p=cnt1[a[i-1]]*qpow(cnt2[a[i-1]][a[i]],mod-2)%mod;
(f[i].k*=p)%=mod;
(f[i].b*=p)%=mod;
// cerr<<f[i].k<<' '<<f[i].b<<'\n';
}
cout<<(1-f[n].b*qpow(f[n].k,mod-2)%mod+mod)%mod;
return 0;
}