HDU 5965 三维dp 或 递推

题意:= =中文题

思路一:比赛时队友想的。。。然后我赛后想了一下想了个2维dp,但是在转移的时候,貌似出了点小问题...吧?然后就按照队友的思路又写了一遍。

定义dp[i][j][k],表示第i列,放j个,剩下k个的种类数。其中j<=2, k<=2,j<=2的来源是只往上、下放。然后状态转移就是

dp[i][j][a[i] - j - k] = (dp[i][j][a[i] - j - k] + p[j] * dp[i - 1][k][j]) % mod;

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha\n")
/*
定义dp[i][j][k]表示第i个人放了j个剩下k个的种类数

*/
const LL mod = 100000007;
const int maxn = 1e4 + 5;
LL dp[maxn][3][6];
char ch[maxn];
int a[maxn];
int n;
LL p[3] = {1, 2, 1};

LL solve(){
    memset(dp, 0, sizeof(dp));
    for (int i = 0; i <= 2; i++) {
        if (a[1] - i > 2) continue;
        if (a[1] - i < 0) break;
        dp[1][i][a[1] - i] = p[i];
    }
    for (int i = 2; i <= n; i++){
        for (int j = 0; j <= 2; j++){
            for (int k = 0; k <= 2; k++){
                if (a[i] - j - k > 2) continue;
                if (a[i] - j - k < 0) break;///目前放入j个,dp[i-1]剩下j个
                dp[i][j][a[i] - j - k] = (dp[i][j][a[i] - j - k] + p[j] * dp[i - 1][k][j]) % mod;
            }
        }
    }
    LL ans = 0;
    for (int i = 0; i <= 2; i++){
        if (i > a[n]) break;
        ans = (ans + dp[n][i][0]) % mod;
    }
    return ans;
}

int main(){
    int t; scanf("%d", &t);
    while (t--){
        scanf("%s", ch);
        n = strlen(ch);
        bool flag = true;
        for (int i = 0; ch[i] != '\0'; i++){
            a[i + 1] = ch[i] - '0';
            if ((i == 0 || i == n - 1) && ch[i] > '4'){
                flag = false; break;
            }
            if (ch[i] > '6') {
                flag = false; break;
            }
        }
        if (!flag) {
            printf("0\n"); continue;
        }
        printf("%I64d\n", solve());
    }
    return 0;
}
View Code

 

思路二:递推

和之前的dp类似,我们定义每次每次都只能往列上放,因此最多只能放两个。然后我们发现,如果第一个位置的地雷数确定了,后面所有的都确定了,那么我们只需要枚举一下,就有答案了

//看看会不会爆int!数组会不会少了一维!
//取物问题一定要小心先手胜利的条件
#include <bits/stdc++.h>
using namespace std;
#pragma comment(linker,"/STACK:102400000,102400000")
#define LL long long
#define ALL(a) a.begin(), a.end()
#define pb push_back
#define mk make_pair
#define fi first
#define se second
#define haha printf("haha\n")
const int maxn = 1e4 + 5;
const LL mod = 100000007;
LL dp[maxn];
char ch[maxn];
int a[maxn];
int n;
int p[3] = {1, 2, 1};

LL solve(){
    LL ans = 0;
    for (int i = 0; i <= 2 && i <= a[1]; i++){
        if (a[1] - i > 2) continue;
        dp[1] = a[1] - i;
        for (int j = 2; j <= n; j++){
            dp[j] = a[j - 1] - dp[j - 1] - dp[j - 2];
        }
        if (dp[n] + dp[n - 1] != a[n]) continue;
        LL res = 1;
        for (int j = 1; j <= n; j++){
            res = res * p[dp[j]];
            if (res > mod) res %= mod;
        }
        ans = (ans + res) % mod;
    }
    return ans;
}

int main(){
    int t; cin >> t;
    while (t--){
        scanf("%s", ch);
        n = strlen(ch);
        bool flag = true;
        for (int i = 0; i < n; i++){
            if ((i == 0 || i == n-1) && ch[i] > '4'){
                flag = false; break;
            }
            if (ch[i] > '6'){
                flag = false; break;
            }
            a[i + 1] = ch[i] - '0';
        }
        if (!flag) {
            printf("0\n"); continue;
        }
        printf("%I64d\n", solve());
    }
    return 0;
}
View Code

 

posted @ 2016-11-05 19:43  知る奇迹に  阅读(548)  评论(0编辑  收藏  举报