题意:一维扫雷,给出0, 1, 2, ?, *,问符合规则的地图有多少种 (长度:1?≤?n?≤?10^6)?
题目链接:http://codeforces.com/contest/404/problem/D
——>>怎么想呢?
看CF的代码看出了这样的想法:
设d[i][j]表示前i个位置(其中第i个位置是类型jj)的正确放置数。。
对于一个位置,共有3种类型:
0 : 该位置不是bomb,且下一个位置也不是bomb;
1 : 该位置不是bomb,且下一个位置是bomb;
2 : 该位置是bomb。
那么,可以得到状态转移方程:
设现在的位置是i,
一、如果是输入的0,
说明这个位置不是bomb,且下一个位置不是bomb,所以只会更新d[i][0],同时,上一个位置也不会是bomb,于是得:
d[i][0] = d[i-1][0];
二、如果是输入的1,
说明这个位置不是bomb,但下一个位置可能是bomb,如果下一个位置是bomb,那么上一个位置不会是bomb,则:
d[i][1] = d[i-1][0];
如果下一个位置不是bomb,那么上一个位置是bomb,则:
d[i][0] = d[i-1][2];
三、如果输入的是2,
说明这个位置不是bomb,下一个位置是bomb,所以只会更新d[i][1],且上一个位置是bomb,于是得:
d[i][1] = d[i-1][2];
四、如果输入的是*,
说明这个位置是bomb,上一个位置可以是bomb,也可以是1,则:
d[i][2] = d[i-1][2] + d[i-1][1];
五、如果输入的是?,说明以上情况都可以,所以情况的数目都要加起来。。
************************************************************************
可以发现,d的第一维可以省略,用滚动数组的思想。。
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 1000000 + 10;
const int mod = 1000000000 + 7;
char s[maxn];
int main()
{
while(scanf("%s", s) == 1) {
long long d[] = {1, 1, 0};
for(int i = 0; s[i]; i++) {
long long t[] = {0, 0, 0};
if(s[i] == ‘0‘ || s[i] == ‘?‘) t[0] += d[0];
if(s[i] == ‘1‘ || s[i] == ‘?‘) {
t[1] += d[0];
t[0] += d[2];
}
if(s[i] == ‘2‘ || s[i] == ‘?‘) t[1] += d[2];
if(s[i] == ‘*‘ || s[i] == ‘?‘) t[2] += d[2] + d[1];
for(int j = 0; j < 3; j++) d[j] = t[j] % mod;
}
printf("%I64d\n", (d[0] + d[2]) % mod);
}
return 0;
}
CF - 404 - D. Minesweeper 1D,布布扣,bubuko.com
原文:http://blog.csdn.net/scnu_jiechao/article/details/23131453