题意:
给出一个长度为N的01串,对这个串做一些操作,使得最后能够只剩下一个1,即这个串是合法的。
每次操作选择三个相邻的数,用它们三个数的中位数替代它们三个数。
现在给出一个串,串的某些位置固定为0或1,还有些位置没有固定,为“?”
求满足条件的合法串的个数。
保证N≤50N≤50且N为奇数。
这又是一道性质题:
首先,转换表达形式:用一个数组,表示每两个相邻的1之间的0的个数(包括两端点),如
0010110010
表示为:
21021
设更改后的每个位置的值为aiai
显然,若ai>2ai>2,那么将其减去一个偶数,对其合法性无影响(即每次选中3个0,删去2个)。
现在a数组中的值固定在[0,2]这个区间内。
再观察当ai=1ai=1时,我们可以在不影响周围的点的情况下,删去这些值,并且显然对其合法性也没有影响。如
(010010100:1212)
可以转化为
(00100:22)
现在,a数组中的值只有0与2两种情况了。
这样想:对于ai=2ai=2,删去这三个数,插入一个0,使得ai+1+1ai+1+1,无论其为什么值,都会被转化为1,然后又回到上面那个问题,同样删去没有影响。
换句话说,每删去一个2,就必须删去其后的一个值。
现在结论就很显然了,若最终的串为合法,必然满足至少存在一个点对(p,q)(p,q)
满足ap=aq=0ap=aq=0且p<qp<q且pp为奇数,
为偶数。
然后写一个DP维护即可(我写的5维状态似乎有点丑,不过应该比较好理解)
即DP[i][j][x][y][z]DP[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);
}