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
*/
posted on 2022-10-06 19:51  HZOI-曹蓉  阅读(7)  评论(0编辑  收藏  举报