2022NOIP模拟A层4 字符串还原 字符串生成
T4【概率期望】给出一个字符01串S,你有一个空串,每次可以在序列末尾加上0或者1,求出现S串的期望长度。(n<=1e6)
首先正推是无穷状态,你可以永远也构造不出来这个S,所以倒推。定义fi表示已经填完i个S串部分,到达终点的期望步数。考虑对于fi可以转移到哪些状态:
如果下一个放的s==M(i+1),可以到fi+1
如果不等于,那么当前状态会回退到一个状态,就是以!s(i+1)结尾的一段前缀和i位置最长前缀匹配。可以通过kmp求。
\(fi=f(i+1)/2+f(fail(i))/2+1\)
\(f(i+1)=2*fi-f(fail(i))-2\)
\(f(n)=0\)
发现\(fi=k*f0+b\)把系数作为递推对象,求出\(fn=k*f0+b,ans=-b/k\)
递归求系数会炸,因为本身就是2次方级别的递推,记忆华也救不了你
点击查看代码
//吾必胜
#include<bits/stdc++.h>
using namespace std;
#define _f(i,a,b) for(register int i=a;i<=b;++i)
#define f_(i,a,b) for(register int i=a;i>=b;--i)
#define ll long long
#define chu printf
inline ll re()
{
ll x=0,h=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')h=-1;ch=getchar();}
while(ch<='9'&&ch>='0'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
return x*h;
}
const int N=1e6+100;
const ll mod=1e9+7;
int nxt[N],fail[N],n;ll fk[N],fc[N];
char s[N];
pair<ll,ll>rem[N];
bool vis[N];
inline ll qpow(ll a,ll b)
{
ll op=1;
while(b)
{
if(b&1)op=op*a%mod;
a=a*a%mod;
b>>=1;
}
return op;
}
// inline pair<ll,ll> dfs(int now)
// {
// // chu("now:%d\n",now);
// if(now<=0)
// {
// //chu("dfsfdsfd\n");
// return make_pair(1,0);
// }
// // chu("go to rem\n");
// if(vis[now])return rem[now];
// // chu("(%d)not rem %d %d\n",now,now-1,fail[now-1]);
// pair<int,int>ar=dfs(now-1);
// // chu("(%d),out half\n",now);
// pair<int,int>br=dfs(fail[now-1]);
// vis[now]=1;
// // chu("(%d),out all\n",now);
// return rem[now]=make_pair(ar.first*2-br.first,ar.second*2-br.second-2);//f[0]+常数
// }
int main()
{
// freopen("monkey.in","r",stdin);
// freopen("1.out","w",stdout);
scanf("%s",s+1);
n=strlen(s+1);
// chu("strlen:%d\n",n);
int j;
if(s[1]!=s[2]) fail[1]=1;
_f(i,2,n)
{
j=nxt[i-1];
while(j&&s[j+1]!=s[i])j=nxt[j];
if(s[j+1]==s[i])++j;
nxt[i]=j;
}
//_f(i,1,n)chu("nxt[%d]:%d\n",i,nxt[i])
s[n+1]='#';
_f(i,2,n)
{
int goal=nxt[i];
while(goal&&s[goal+1]==s[i+1])goal=nxt[goal];
if(s[goal+1]!=s[i+1])goal++;
fail[i]=goal;
// chu("fail[%d]:%d\n",i,fail[i]);
}
fk[0]=1,fc[0]=0;
fk[1]=1;fc[1]=-2+mod;
_f(i,2,n)
{
fk[i]=(2*fk[i-1]-fk[fail[i-1]])%mod;
fc[i]=(2*fc[i-1]-fc[fail[i-1]]-2+mod)%mod;//不能取模数?
}
// chu("fk:%lld fc:%lld\n",fk[n],fc[n]);
// fc[n]=(-fc[n]+(cnt+1)*mod)%mod;
fc[n]=(-fc[n]+mod)*qpow(fk[n],mod-2)%mod;
chu("%lld",fc[n]);
return 0;
}
/*
nxt[i]:i满足要求,i+1发现不符合要求时对于符合要求的最长前缀
nxt[i]处理好了
ans[i]
j=nxt[i]
while(s[j+1]==s[i+1])j=nxt[j];
0101111000001011
*/