HDU 3565 Bi-peak Number(数位DP)

题目链接:HDU 3565

题目大意:定义“双峰数”为满足可以分割成两个 /\ /\ 的形式的数,求区间[L,R]内双峰数位数和的最大值。

题解:第一次写数位DP,开篇BLOG记录一下 ○(>_<)○
用记忆化搜索实现,dfs(int wei,int cur,int sta,bool fdn,bool fup)表示当前填到第wei位,上一位数字是cur,双峰数的状态为sta,这一位的取值是(true)否(false)可能顶到上(fdn)下(fup)界时已经填的数位和最大值。
这里sta=0~6分别表示:0还没有开始填,1走到了第一个峰的上坡但是下一步不能直接向下走,2走到了第一个峰的上坡并且下一步可以向上也可以向下走,3走到了第一个峰的下坡处,4走到了第二个峰的上坡但是下一步不能直接向下走,5并且下一步可以向上也可以向下走,6走到了第二个峰的下坡并且之后之能向下走。大概是下面的样子:

      _2_           _5_
    /     \       /     \
  1/       \3   4/       \6
  /         \   /         \
0            (_)           \

转移的时候枚举下一位填什么数(注意上下界),判断双峰数的状态,没有顶到上下界的部分可以记忆化。代码在下面:

code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
typedef unsigned long long ll;
inline ll read()
{
    char c=getchar(); ll num=0,f=1;
    while (c<'0'||c>'9') { if (c=='-') f=-1; c=getchar(); }
    while (c<='9'&&c>='0') { num=num*10+c-'0'; c=getchar(); }
    return num*f;
}
ll T,L,R;
int dp[21][11][7],r[21],l[21];
int dfs(int wei,int cur,int sta,bool fdn,bool fup)
{
    if (wei==0) return (sta==6)?0:-1;
    if (!fdn&&!fup&&(~dp[wei][cur][sta])) return dp[wei][cur][sta];
    int mn=(fdn?l[wei]:0),mx=(fup?r[wei]:9),ret=-1;
    for (int i=mn;i<=mx;i++)
    {
        int tmp;
        switch (sta)
        {
            case 0: tmp=i?1:0; break;
            case 1: tmp=(i>cur)?2:-1; break;
            case 2: tmp=(i>cur)?2:((i<cur)?3:-1); break;
            case 3: tmp=(i<cur)?3:4; break;
            case 4: tmp=(i>cur)?5:-1; break;
            case 5: tmp=(i>cur)?5:((i<cur)?6:-1); break;
            case 6: tmp=(i<cur)?6:-1; break;
        }
        if (~tmp)
        {
            int num=dfs(wei-1,i,tmp,fdn&&i==mn,fup&&i==mx) ;
            if (~num) ret=max(ret,num+i);
        }
    }
    if (!fdn&&!fup) dp[wei][cur][sta]=ret;
    return ret;
}
int main()
{
    T=read(); memset(dp,-1,sizeof(dp));
    for (int i=1;i<=T;i++)
    {
        L=read(); R=read(); l[0]=r[0]=0;
        while (R)
        {
            l[++l[0]]=L%10,L/=10;
            r[++r[0]]=R%10,R/=10;
        }
        int ans=dfs(r[0],0,0,1,1); if (ans==-1) ans=0;
        printf("Case %d: %d\n",i,ans);
    }
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值