有一个 1 维的扫雷游戏,每个格子用表示有雷,用 0/1/2 表示无 雷并且相邻格子中有 0/1/2 个雷。 给定一个仅包含?、、0、1、2 的字符串 S,问有多少种方法将所 有的?改为/0/1/2 使其合法。
输入一个字符串S,输出一行一个整数表示答案,对10^9+7取模。
?1?
2
对于30%的数据,|S|<=20。
对于60%的数据,|S|<=1000。
对于100%的数据,|S|<=10^6。
目前对于自己没有思路的题暂时使用copy代码加自己的注释和文末总结吧.的确智商捉急哈
源自CSDN题解
老哥代码写的很简洁明了啦
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; long long n,ans,f[1000005][10]; char a[1000005]; int main(){ scanf("%s",a); n=strlen(a); if (a[0]=='*') f[0][4]=f[0][5]=1;//到1下一个是雷和下一个不是雷的可能都为1 if (a[0]=='0') f[0][0]=1;//那么下一个必然不为雷的种数为1 if (a[0]=='1') f[0][2]=1;//下一个必然为雷1 if (a[0]=='2' || a[n-1]=='2') {puts("0"); return 0;}//由于在两端,最多周围只可能有一个雷 if (a[0]=='?') f[0][0]=f[0][2]=f[0][4]=f[0][5]=1;//如果不确定,那么因为对于下一块,每一种可能的种数都加一 for (int i=1; i<n; i++) { if (a[i]=='*' || a[i]=='?')//这个是雷 { f[i][4]=f[i][5]=(f[i-1][2]+f[i-1][3]+f[i-1][4])%(1000000007);//这个是雷的种数是 上一个为1且下一个为雷的种数 加上 一个为2且下一个为雷的种数 加上 上一个为雷且下一个为雷的种数 } if (a[i]=='0' || a[i]=='?')//这周围没有雷的种数是 上一个是1下一个不是雷的种数 + 上一个是0的种数 { f[i][0]=(f[i-1][1]+f[i-1][0])%(1000000007); } if (a[i]=='1' || a[i]=='?')//这个是1的种数 { f[i][2]=(f[i-1][1]+f[i-1][0])%(1000000007);//右边是雷 上一个不是雷且下一个不是雷的两种情况的种数之和 f[i][1]=f[i-1][5];//左边是雷 } if (a[i]=='2' || a[i]=='?')//两边都是雷 { f[i][3]=f[i-1][5];//上一个是雷且下一个不是雷的种数 } } n--;//0- (n-1) ans=(f[n][0]+f[n][1]+f[n][5])%(1000000007);//最后一个的下一个必然不可能为雷 printf("%lld",ans); } /* 0 0(下一个不是雷) 1 1(下一个不是雷) 2 1(下一个是雷) 3 2(下一个是雷) 4 *(下一个是雷) 5 *(下一个不是雷) */
总体来看思路还是很明确的,第i个为哪一种可能的种数仅于上一个的种数有关系,DP的无后效性是指的一个之后吗???