题解:P12607 三叉求和
点
注意到有用状态数远小于
#include <bits/stdc++.h>
#define rep(i,k,n) for(int i=k;i<=n;++i)
#define per(i,n,k) for(int i=n;i>=k;--i)
using namespace std;
template<typename T>
inline void read(T &x){
x=0;int f=1;char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+(c-'0');
x*=f;
}
template<typename T,typename ...Args>
inline void read(T &x,Args &...rest){read(x);read(rest...);}
const int N=3e3+10,MOD=1e9+7;
int n,a[N*3],vis[N*3],f[2][2*N][2*N];
vector<pair<int,int> > use[2];
string s;
vector<int> tran[2][N*2];
signed main(){
read(n);
cin>>s;
reverse(s.begin(),s.end());
rep(i,1,n){
if(s[i-1]=='?') a[i]=-1;
else a[i]=s[i-1]-'0';
}
rep(i,0,2*n) if(a[1]==-1||(i%3)==(a[1]%3)){
f[1][i][i]=1,tran[1][i].push_back(i),use[1].push_back({i,i});
}
int i1=0,i2=1;
rep(i,1,n){
i1^=1;i2^=1;
for(auto p:use[i2]) f[i2][p.first][p.second]=0;
use[i2].clear();
rep(j,0,2*(n-i+2)) tran[i2][j].clear();
rep(j,0,2*(n-i+1)){
for(auto k:tran[i1][j]){
if(vis[k]) continue;vis[k]=1;
if(f[i1][j][k]==0) continue;
rep(x,0,2){
int j2=j-x;if(j2<0) break;
int num=(k/3)+j2;
if(a[i+1]!=-1&&a[i+1]%3!=num%3) continue;
(f[i2][j2][num]+=f[i1][j][k])%=MOD;
use[i2].push_back({j2,num});
tran[i2][j2].push_back(num);
}
}
for(auto k:tran[i1][j]) vis[k]=0;
}
}
printf("%d\n",f[i2][0][0]);
return 0;
}