HDU-5965 mine clearance

Title meaning: 3 * n has a minesweeper, wherein the middle line is not mine and all lattice points is open, the middle row gives the figures, there are several mined According string of numbers on both sides of Statistics

Sample input:

2

22

000

Sample output:

6

1

Link to the original question: http://acm.hdu.edu.cn/showproblem.php?pid=5965


For the laying of mines issue, we first note that if a mine is planted, the information in this mine will be shared by three grid around it, but outside the grid of three little effect on the grid

In turn we can expect for the numbers in the middle row of a grid, it only affects the display of thunder up and down within three grid

This will give us a dp inspiration, is the i-th to the middle of the grid, the number placed in the program launched by the grid should be able to put several known solutions to the front of the grid, and this is a recursive relationship between multiplication recursion, is placed in the grid should be equal to the number of programs it put before the grid multiplied by the number of programs now that it is the number of lattice tips that can put digital programs.

Model for dp, we have a visual idea is to use the f [i] represents the number placed in the i-th program grid, so f [n] is the answer we need, and then began to think of the state transition equation

But we found that, although the information outside of the three cells can be directly calculated as part of the multiplication of the number of programs, but because of the numbers in the three cells of the tips of the mined information is shared, resulting in a simple f [i] push here i can not move, because i can prompt information lattice only the first of several, does not involve the specific information put mine, so i took only one correct state transition equation is impossible to get out. In this case, we have to consider increasing the state information, and such information involves the laying of mines method, so our task becomes how to get reasonable design state, so that these states can mined situation represented.

 

Here three design solution is to increase the information a, b, c, respectively, buried in the i-th digit, and the left figure of a mine-discharge, the intermediate mine-b put right put a mine-c

Then becomes an array f [i] [a] [b] [c], is provided for the i-th digit num [i], the answer is that we need f [n] [a] [b] [0] where a + b = num [i], that is, for the last number we can not go down to put it on the right thunder

这样子设计有什么好处呢?如果第i个数字的左边放了a个雷,中间放了b个雷,对于第i-1个数字来说就是中间放了a个雷,右边放了b个雷,就是对于f[i]跟f[i-1]来说,由于a跟b的两个信息的共享,f[i]跟f[i-1]的关系变得清晰了,那么我们就很容易推知f[i][a][b][c] = f[i-1][num[i-1] - a - b][a][b] * (数字i的右边摆c颗雷的方案数),其中a+b+c = num[i],意思是对于第i个数字来说,它周围的雷就必须是这么多,而num[i-1] - a - b的意思是既然第i-1个数字的右边跟中间分别放了a颗雷跟b颗雷,那么它的左边就只能放num[i-1] - a - b颗雷了,需要注意的是这个数可能会是负数也有可能大过2,这种情况说明了不存在这种abc摆雷方案,让整个式子等于0即可,而数字i右边摆c颗雷的方案数,我们知道这个c只能等于0,1, 2,那么我们就可以预处理个solution[3]数组把这些相应的摆雷方案数存下来即可。

 

至于初始状态,这个也好弄,就是第一个数字,我们不能往左边格子放雷,也就是a = 0,b+c = num[1]的情况,f[1]单独拿出来算一次我们就能得到初始状态了。

所以这里的整个状态方程就是

直接看公式我自己都觉得头大,大家看看上边的分析自己看着写即可


 贴上AC代码:

#include<iostream>
#include<cstring>
#include<string>
#define _rep(i, l, r) for(int i=l; i<=r ;i++)
using namespace std;

const int Maxn = 1e4 + 10;
const int M = 100000007;
int num[Maxn];
int f[Maxn][3][3][3];

int solution[3] = { 1, 2, 1 };

void Ini()
{
    memset(num, 0, sizeof(num));
    memset(f, 0, sizeof(f));
}

void Input(string& str)
{
    cin >> str;
    for (int i = 0; i < str.size(); i++) {
        num[i+1] = str[i] - '0';
    }
}

void solve(int n)
{
    _rep(b, 0, 2) _rep(c, 0, 2) {
        if (b + c != num[1]) continue;
        f[1][0][b][c] = solution[b] * solution[c];
    }

    for (int i = 2; i <= n; i++) {
        _rep(a, 0, 2) _rep(b, 0, 2) _rep(c, 0, 2) {
            if (a + b + c != num[i]) continue;
            int res = num[i - 1] - a - b;
            if (res < 0 || res > 2) continue;
            f[i][a][b][c] = (f[i][a][b][c] + solution[c] * f[i - 1][res][a][b]) % M;
        }
    }

    int ans = 0;
    _rep(a, 0, 2) _rep(b, 0, 2) {
        if (a + b != num[n]) continue;
        ans = (ans + f[n][a][b][0]) % M;
    }

    cout << ans << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    int T;
    cin >> T;
    while (T--){
        string str;
        Ini();
        Input(str);
        int n = str.size();
        solve(n);
    }
    
    return 0;
}

 

Guess you like

Origin www.cnblogs.com/wulichenai/p/12346766.html