现在的位置: 首页 > 综合 > 正文

CF – 404 – D. Minesweeper 1D(dp)

2019年08月31日 ⁄ 综合 ⁄ 共 1206字 ⁄ 字号 评论关闭

题意:一维扫雷,给出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;
}

抱歉!评论已关闭.