mine:dp
一个小的线性dp。方法很多,八仙过海各显神通。
我想讲一下我的:
1 #include<cstdio> 2 #define mod 1000000007 3 char s[1000005];int dp[1000005][2][2],n;//是不是雷,右边有没有雷 4 int main(){ 5 scanf("%s",s+1); 6 for(n=1;s[n];n++);n--; 7 dp[0][0][0]=dp[0][0][1]=1; 8 for(int i=1;i<=n;++i) 9 if(s[i]=='0')dp[i][0][0]=dp[i-1][0][0]; 10 else if(s[i]=='1')dp[i][0][0]=dp[i-1][1][0],dp[i][0][1]=dp[i-1][0][0]; 11 else if(s[i]=='2')dp[i][0][1]=dp[i-1][1][0]; 12 else if(s[i]=='*')dp[i][1][1]=dp[i][1][0]=(dp[i-1][0][1]+dp[i-1][1][1])%mod; 13 else { 14 dp[i][0][0]=dp[i-1][0][0];//0 15 (dp[i][0][0]+=dp[i-1][1][0])%=mod;dp[i][0][1]=dp[i-1][0][0];//1 16 (dp[i][0][1]+=dp[i-1][1][0])%=mod;//2 17 dp[i][1][1]=dp[i][1][0]=(dp[i-1][0][1]+dp[i-1][1][1])%mod;//* 18 } 19 printf("%d\n",(dp[n][0][0]+dp[n][1][0])%mod); 20 }
我的dp含义是:dp[i][this][next]表示考虑了第i位后,this和next位置上有没有雷的方案数。
思考一下:如果你知道前面的一位是什么,这一位是什么,你就能推断出下一位是什么。
因为在一维扫雷里只有相邻的3个格子之间有约束作用。
所以我们来考虑dp[i][t][n]由什么转移而来:
如果第i位是个’0‘,那么它不是雷,它的前面一位不能是雷,后面也不能是,则dp[i][0][0]=dp[i-1][0][0](注意文字与代码的颜色对应)
如果是个’1‘,那么它不是雷,分2种情况:
它前面有而后面没有:dp[i][0][0]=dp[i-1][1][0];
它前面没有而后面有:dp[i][0][1]=dp[i-1][0][0];
如果是个’2‘,那么它不是雷,而前后都有雷:dp[i][0][1]=dp[i-1][1][0];
如果它是个雷,那么前面随意。。后面也随意。。:dp[i][1][1]=dp[i][1][0]=dp[i-1][0][1]+dp[i-1][1][1];
如果是个问号就把上面这些状态都弄一遍就好。
初状态dp[0][0][0]=dp[0][0][1]=1因为第0个格子上没有雷而它的右边有没有再说并不会被第0个格子限制。
末状态dp[n][1][0]+dp[n][0][0]因为并不在意第n个格子上有没有雷(如果它不合法那么dp值为0),而第n+1个格子上没有雷。
完毕!
$Fate \ is \ Fake$