[DP][AGC022E] Median Replace

· · 个人记录

[AGC022E] Median Replace

考虑如何判定一个序列合法

观察发现如果操作的三个数不相同,整个序列 10 的相对个数不改变 , 可以看成不同的两个数相抵消。

而操作相同的三个数时,这个数的总数减 2

所以只要某个时刻 1 的个数比 0 多即可。所以策略应该是尽量多使得三个 0 连在一起被消掉,考虑用栈模拟这个过程

可以得到:

f_{i,j,k} 表示前 i 个数的栈中有 j0 , k1 ,按上面转移即可。

#include <bits/stdc++.h>
using namespace std;
#define ll long long
//#define LOCAL
constexpr ll mo=1e9+7;
char s[300005];
int n;
ll f[300005][3][3]; 
signed main()
{
    #ifdef LOCAL
    freopen(".in","r",stdin);
    freopen(".out","w",stdout);
    #endif
    scanf("%s",s+1);n=strlen(s+1);
    f[0][0][0]=1;
    for (int i=1;i<=n;i++)
    {
        if (s[i]!='1')
            for (int j=0;j<=2;j++) f[i][1][j]=(f[i-1][0][j]+f[i-1][2][j])%mo,f[i][2][j]=f[i-1][1][j];
        if (s[i]!='0')
        {
            f[i][0][1]=f[i-1][0][0],f[i][0][2]=(f[i-1][0][1]+f[i-1][0][2])%mo;
            for (int j=1;j<=2;j++) 
                for (int k=0;k<=2;k++) f[i][j-1][k]=(f[i][j-1][k]+f[i-1][j][k])%mo;
        }
    }
    ll ans=0;
    for (int i=0;i<=2;i++)
        for (int j=i;j<=2;j++) ans=(ans+f[n][i][j])%mo;
    printf("%lld\n",ans); 
    return 0;
}
/**/