Median Replace,agc022E,困难的性质推导

正题

      首先考虑到3个0的肯定可以先删掉,那么两个1之间最多只有两个0。

      把一个序列写成0,1,2三个数字组成的形式,分别表示在第i个1和第i-1个1之间0的个数,首尾情况考虑先插一个1.

      然后发现单独的0的情况其实是可以直接删除的,除非只剩下一个0,因为附近肯定有一个1,所以,01不论与1还是与0结合,都会生成一个与结合数字相同的数字,去掉它对正确性并没有影响,因为接下来的操作对于每一个0块独立。

      那么现在只剩下一个只存在02的长度为偶数的数列,那么我们需要经过一波操作使得剩下的数列为00.(代表中间有一个1)

      找规律可以发现,两个0可以与周围的一个1结合生成一个0,而这个0,会与相邻的0个0或者2个0,生成1个0,也就是说去掉一个2,要使相邻的其中一个变为1,然后变为1了,就可以直接删除了,所以对于这样的数列来说,一删就是删两个。

       可以证明,只有当分别存在一个奇数位上的0和一个偶数位上的0时,才会剩下00,具体怎么证明可以暴力枚举其他的情况。

       那么就可以构造一个Dp,完结撒花。

       另外一种很神奇的做法就是毕克自动机,我也不知道为什么是对的,也不知道怎么构造的,详见其他的Blog。

#include<bits/stdc++.h>
using namespace std;

long long f[2][3][2][3];//状态,位置,0个数 
const long long mod=1e9+7;
int n;
char s[1000010];

int main(){
	int op=0;
	f[0][0][1][0]=1;
	scanf("%s",s+1);
	n=strlen(s+1);s[n+1]='1';
	for(int i=1;i<=n+1;i++){
		op^=1;memset(f[op],0,sizeof(f[op]));
		if(s[i]!='0'){
			f[op][0][1][0]+=f[op^1][0][0][0]+f[op^1][0][0][2]+f[op^1][0][1][1];
			f[op][0][0][0]+=f[op^1][0][0][1]+f[op^1][0][1][2];
			f[op][1][1][0]+=f[op^1][1][0][2]+f[op^1][1][1][1];
			f[op][1][0][0]+=f[op^1][0][1][0]+f[op^1][1][1][0]+f[op^1][1][1][2]+f[op^1][1][0][1];
			f[op][2][1][0]+=f[op^1][1][0][0]+f[op^1][2][0][2]+f[op^1][2][1][1]+f[op^1][2][0][0];
			f[op][2][0][0]+=f[op^1][2][1][2]+f[op^1][2][1][0]+f[op^1][2][0][1];
		}
		if(s[i]!='1'){
			for(int j=0;j<3;j++)
				for(int k=0;k<2;k++)
					f[op][j][k][2]+=f[op^1][j][k][1],f[op][j][k][1]+=f[op^1][j][k][2]+f[op^1][j][k][0];
		}
		for(int j=0;j<3;j++)
			for(int k=0;k<2;k++)
				for(int q=0;q<3;q++) f[op][j][k][q]%=mod;
	}
	printf("%lld",(f[op][2][0][0]+f[op][2][1][0])%mod);
}

     

猜你喜欢

转载自blog.csdn.net/Deep_Kevin/article/details/103497478