【DP】[Atcoder Grand Contest 022]E Median Replace

题意:

给出一个长度为N的01串,对这个串做一些操作,使得最后能够只剩下一个1,即这个串是合法的。
每次操作选择三个相邻的数,用它们三个数的中位数替代它们三个数。
现在给出一个串,串的某些位置固定为0或1,还有些位置没有固定,为“?”
求满足条件的合法串的个数。
保证 N 50 且N为奇数。


这又是一道性质题:
首先,转换表达形式:用一个数组,表示每两个相邻的1之间的0的个数(包括两端点),如
0010110010
表示为:
21021

设更改后的每个位置的值为 a i
显然,若 a i > 2 ,那么将其减去一个偶数,对其合法性无影响(即每次选中3个0,删去2个)。

现在a数组中的值固定在[0,2]这个区间内。

再观察当 a i = 1 时,我们可以在不影响周围的点的情况下,删去这些值,并且显然对其合法性也没有影响。如
(010010100:1212)
可以转化为
(00100:22)

现在,a数组中的值只有0与2两种情况了。
这样想:对于 a i = 2 ,删去这三个数,插入一个0,使得 a i + 1 + 1 ,无论其为什么值,都会被转化为1,然后又回到上面那个问题,同样删去没有影响。
换句话说,每删去一个2,就必须删去其后的一个值。

现在结论就很显然了,若最终的串为合法,必然满足至少存在一个点对 ( p , q )
满足 a p = a q = 0 p < q p 为奇数, q 为偶数。

然后写一个DP维护即可(我写的5维状态似乎有点丑,不过应该比较好理解)
D P [ i ] [ j ] [ x ] [ y ] [ z ] 表示前i个位置,
当前的合法性为j(j=0,1,2分别表示:既没有p也没有q(0),已经找到了一个p(1),已经找到了一对(p,q)(2))
前一个位置的状态x(x=0,1)
当前的位置在a数组中的奇偶性y,
前面一个连续的0的长度的奇偶性z

转移很简单,实在不会看代码吧。

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#define SF scanf
#define PF printf
#define MAXN 300010
#define MOD 1000000007
using namespace std;
typedef long long ll;
int a[MAXN],len;
char s[MAXN];
ll dp[MAXN][3][2][2][2];
int main(){
    SF("%s",s);
    int len=strlen(s);
    s[len]='1';
    dp[0][0][0][0][0]=1;
    for(int i=0;i<=len;i++)
        for(int j=0;j<3;j++)
            for(int las=0;las<2;las++)
                for(int pos=0;pos<2;pos++)
                    for(int sz=0;sz<2;sz++)
                        for(int tag=0;tag<2;tag++){
                            if(s[i]=='0'&&tag==1)
                                continue;
                            if(s[i]=='1'&&tag==0)
                                continue;
                            if(tag==1){
                                if((las==1||i==0)&&pos==0)
                                    dp[i+1][max(1,j)][tag][pos^1][0]=(dp[i+1][max(1,j)][tag][pos^1][0]+dp[i][j][las][pos][sz])%MOD;
                                if((las==1||i==0)&&pos==1)
                                    dp[i+1][2*(j>=1)][tag][pos^1][0]=(dp[i+1][2*(j>=1)][tag][pos^1][0]+dp[i][j][las][pos][sz])%MOD;
                                if(las==0&&i!=0&&sz==1)
                                    dp[i+1][j][tag][pos][0]=(dp[i+1][j][tag][pos][0]+dp[i][j][las][pos][sz])%MOD;
                                if(las==0&&i!=0&&sz==0)
                                    dp[i+1][j][tag][pos^1][0]=(dp[i+1][j][tag][pos^1][0]+dp[i][j][las][pos][sz])%MOD;
                            }
                            if(tag==0){
                                dp[i+1][j][tag][pos][sz^1]=(dp[i][j][las][pos][sz]+dp[i+1][j][tag][pos][sz^1])%MOD;
                            }
                        }
    ll ans=0;
    for(int i=0;i<2;i++)
        for(int j=0;j<2;j++)
            for(int k=0;k<2;k++)
                ans=(ans+dp[len+1][2][i][j][k])%MOD;
    PF("%lld",ans);
} 

猜你喜欢

转载自blog.csdn.net/qq_34454069/article/details/79836319