题目:
分析:
这个数据范围只能做线性递推或加一个log。而这道题要求方案数,很容易联想到dp。主要是dp的转移情况多且复杂。
特别要考虑1,因为可能是1的前面或后面有*,于是就将1的情况一分为二:前面的1和后面的1(指的是*1的前面还是后面)
考虑每一位能够由前一位的哪些状态转移过来:
0: 前1和0
前1: *
后1: 0 和 前1
* : 后1 和 2 和 *
2: *
?:前面转移的都可以转移一遍,因为这一位可以填很多种
然后设dp[ i ] [ 0/1/2/3 ] [ 0/1 ]为递推到第i位,这一位填0或1或*或2 的方案数,最后一维0表示前1,1表示后1。
注意初始化和输出。
#include<bits/stdc++.h> using namespace std; #define ll long long #define N 1000005 const ll mod=1e9+7; ll dp[N][5][3]; char s[N]; int main() { freopen("mine.in","r",stdin); freopen("mine.out","w",stdout); scanf("%s",s+1); int len=strlen(s+1); if(s[1]=='?') dp[1][0][0]=1,dp[1][2][0]=1,dp[1][1][1]=1; else if(s[1]=='0') dp[1][0][0]=1; else if(s[1]=='*') dp[1][2][0]=1; else if(s[1]=='1') dp[1][1][1]=1; //2->* for(int i=2;i<=len;i++) if(s[i]=='0'){ dp[i][0][0]=(dp[i-1][0][0]+dp[i-1][1][0])%mod; } else if(s[i]=='1'){ dp[i][1][0]=dp[i-1][2][0]; dp[i][1][1]=(dp[i-1][0][0]+dp[i-1][1][0])%mod;// } else if(s[i]=='2'){ dp[i][3][0]=dp[i-1][2][0]; } else if(s[i]=='*'){ dp[i][2][0]=(dp[i-1][2][0]+dp[i-1][1][1]+dp[i-1][3][0])%mod;// } else if(s[i]=='?'){ dp[i][0][0]=(dp[i-1][1][0]+dp[i-1][0][0])%mod; dp[i][1][0]=dp[i-1][2][0]; dp[i][1][1]=(dp[i-1][1][0]+dp[i-1][0][0])%mod;// dp[i][2][0]=(dp[i-1][2][0]+dp[i-1][1][1]+dp[i-1][3][0])%mod;//+dp[i-1][3][0] dp[i][3][0]=dp[i-1][2][0]; } if(s[len]=='?') printf("%lld\n",(dp[len][0][0]+dp[len][1][0]+dp[len][2][0])%mod); else if(s[len]=='0') printf("%lld\n",dp[len][0][0]); else if(s[len]=='1') printf("%lld\n",dp[len][1][0]); else if(s[len]=='*') printf("%lld\n",dp[len][2][0]); else printf("0\n"); return 0; } /* ?1? 1??1 *2*?? ??? ?? 0?*?*100???*2??0??? 0?*?*100???*2*?0??? */