题目链接
首先这题是一个dp。
这种变化有一个非常显然的规律,如果有连续的两个颜色相同,那么往上这两个的颜色都不会变化。
所以我们可以将连续
≥
2
\geq 2
≥2的相同的颜色的快看作一个断点。
然后设
d
p
i
,
c
o
l
,
l
dp_{i,col,l}
dpi,col,l表示有一个断点在
i
i
i这个断点的颜色为
c
o
l
col
col,黑格子的快熟为l的方案数。
i
i
i只是这个断点的右端点,我们需要枚举左端点j(
j
<
i
j<i
j<i),和前一个断点的结尾
k
k
k,然后转移时还要加上
(
k
,
j
)
(k,j)
(k,j)的贡献。
由于时环上,我们需要枚举环上断开的点(第一个断点的开始位置)
时间复杂度
(
n
5
+
n
2
∗
l
)
(n^5+n^2*l)
(n5+n2∗l)其实可以优化成
O
(
n
5
)
O(n^5)
O(n5)的。
/*
{By GWj
*/
#pragma GCC optimize(2)
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define R(a) cin>>a
#define R2(a,b) cin>>a>>b
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXN=105;
LL dp[MAXN][2][MAXN];
bool check[MAXN][MAXN][2][2];
int have[MAXN][MAXN][2][2];
int a[MAXN];
int t;
int vv[MAXN],v[3];
inline int calc(int l,int r,int c1,int c2){
if(l==r-1){
return 0;
}
a[l]=c1;
a[r]=c2;
int is=c1^1;
rb(i,l,r){
is^=1;
a[i]=is;
}
rb(i,1,t){
rb(j,l+1,r-1){
v[0]=(a[j-1]);
v[1]=(a[j+1]);
v[2]=(a[j]);
if(v[1]==v[2]||v[1]==v[0]){
vv[j]=v[1];
}
else{
vv[j]=v[0];
}
}
rb(j,l+1,r-1){
a[j]=vv[j];
}
}
int cnt=0;
rb(j,l+1,r-1)
cnt+=a[j];
return cnt;
}
bool exi[MAXN][MAXN][2];
class GameOfLifeDivOne{
public:
LL theCount(string s, int T, int L){
memset(check,0,sizeof(check));
t=T;
int n=s.length();
n<<=1;
rep(i,n)
s+=s[i];
s='#'+s;
rb(l,1,n)
rb(r,l,n)
rb(i,l,r)
if(s[i]!='?')
exi[l][r][s[i]-'0']=1;
rb(l,1,n)
rb(r,l,n){
rep(c1,2){
rep(c2,2){
bool need=c1^1;
check[l][r][c1][c2]=1;
rb(k,l,r){
need^=1;
if((s[k]-'0')==need||(s[k]=='?')){
continue;
}
check[l][r][c1][c2]=0;
}
if(need!=c2) check[l][r][c1][c2]=0;
}
}
}
rb(l,1,n)
rb(r,l,n)
rep(c1,2)
rep(c2,2){
if(check[l][r][c1][c2]){
have[l][r][c1][c2]=calc(l,r,c1,c2);
}
}
LL rest=0;
n>>=1;
if(check[1][n][0][1]&&calc(0,n+1,1,0)>=L){
rest++;
}
if(check[1][n][1][0]&&calc(0,n+1,0,1)>=L){
rest++;
}
if(!exi[1][n][0]){
rest+=1;
}
if(!exi[1][n][1]&&!L){
rest+=1;
}
rb(bound,1,n){//破环成链的位置
rep(fir_col,2){
memset(dp,0,sizeof(dp));
rb(i,2,n){
if(!exi[bound][bound+i-1][!fir_col]){
dp[i][fir_col][(fir_col? i:0)]=1;
}
}
rb(i,2,n){
rb(wtf,0,n)
rep(col,2){
rb(j,1,i-1){
if(j+bound-1>n) break;
if(exi[j+bound-1][i+bound-1][col^1]) continue;
rb(k,1,j-1){
rep(col_pre,2){
if(k==j-1&&col_pre==col) continue;
if(!check[k+bound-1][j+bound-1][col_pre][col]) continue;
int tmp=wtf-(col? i-j+1:0);
tmp-=have[k+bound-1][j+bound-1][col_pre][col];
if(tmp>=0){
dp[i][col][wtf]+=dp[k][col_pre][tmp];
}
}
}
}
}
}
rb(i,2,n){
rep(col,2){
if(check[i+bound-1][n+bound][col][fir_col]){
int hav=have[i+bound-1][n+bound][col][fir_col];
rb(wtf,0,n){
if(hav+wtf>=L){
rest+=dp[i][col][wtf];
}
}
}
}
}
}
// cout<<"#"<<bound<<" "<<rest<<endl;
}
return rest;
}
}solver;
//int main(){
// cout<<solver.theCount("?????????1???0???1??1??????0??????0??0????1???????",
//12,
//40);
//}
/*
6 5 0
1?0?1?
*/