HDU 3565 Bi-peak Number(数位DP)题解

题意:我们定义每一位先严格递增(第一位不为0)后严格递减的数为峰(比如1231),一个数由两个峰组成称为双峰,一个双峰的价值为每一位位数和,问L~R双峰最大价值

思路:数位DP。显然这个问题和pos有关,和前一项有关,和当前状态有关,我们定义dp[i][j][k]第i位前面j状态k的后面的最佳情况。

状态有7种:

0什么都没,1刚开始第一个上坡,2已经第一个上坡了可以转折了,3第一个下坡0
4刚开始第二个上坡,5已经第二个上坡可以转折了,6第二个下坡

然后数位DP一下就好了。

注意,要开ull,30多个wa的教训

代码:

#include<set>
#include<map>
#include<cmath>
#include<queue>
#include<cstdio>
#include<vector>
#include<cstring>
#include <iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 10000 + 10;
const ull seed = 131;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
int dp[30][10][10];
//0什么都没,1刚开始第一个上坡,2已经第一个上坡了,3第一个下坡0
//4刚开始第二个上坡,5已经第二个上坡,6第二个下坡
//第i位前面j状态k的后面的最佳情况
int top[30], low[30];
int dfs(int pos, int pre, int st, bool MAXflag, bool MINflag){
    if(pos == -1)
        return st == 6? 0 : -INF;
    if(!MINflag && !MAXflag && dp[pos][pre][st] != -1)
        return dp[pos][pre][st];
    int Min = MINflag? low[pos] : 0;
    int Max = MAXflag? top[pos] : 9;
    int ans = -INF;
    for(int i = Min; i <= Max; i++){
        int newSt;
        if(st == 0){
            if(i == 0) newSt = 0;
            else newSt = 1;
        }
        else if(st == 1){
            if(i <= pre) continue;
            if(i > pre) newSt = 2;
        }
        else if(st == 2){
            if(i == pre) continue;
            if(i < pre) newSt = 3;
            else newSt = 2;
        }
        else if(st == 3){
            if(i < pre) newSt = 3;
            else if(i > pre) newSt = 4;
            else{
                if(i) newSt = 4;
                else continue;
            }
        }
        else if(st == 4){
            if(i <= pre) continue;
            newSt = 5;
        }
        else if(st == 5){
            if(i == pre) continue;
            if(i > pre) newSt = 5;
            else newSt = 6;
        }
        else if(st == 6){
            if(i >= pre) continue;
            newSt = 6;
        }
        ans = max(ans, i + dfs(pos - 1, i, newSt, MAXflag && i == Max, MINflag && i == Min));
    }
    if(!MAXflag && !MINflag)
        dp[pos][pre][st] = ans;
    return ans;
}
int solve(ull l, ull r){
    int pos = 0;
    while(r){
        top[pos] = r % 10;
        low[pos++] = l % 10;
        r /= 10;
        l /= 10;
    }
    int ans = dfs(pos - 1, 0, 0, true, true);
    return max(0, ans);
}
int main(){
    int t, ca = 1;
    memset(dp, -1, sizeof(dp));
    scanf("%d", &t);
    while(t--){
        ull l, r;
        cin >> l >> r;
        printf("Case %d: %d
", ca++, solve(l, r));
    }
    return 0;
}
原文地址:https://www.cnblogs.com/KirinSB/p/10727197.html