题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=3565
题目大意:
各位数字先增后减的数称为峰值数(位数大于等3且第一位非零),然后两个峰值数连在一起是一个bi-peak数,求两个数之间bi-peak数的各位数字之和的最大值。
解题思路:
数位dp,dp[i][j][k]表示当前后面还有i位,j表示前一位的数字,k表示与峰值的状态关系。
k=0 表示前面的为零,k=1表示前面恰好有一个在第一个波峰的上坡上,k=2表示前面至少有两个在第一个波峰的上坡上,k=3表示在第一个波峰的下坡上
k=4表示前面恰好有一个在第二个波峰的上坡上,k=5表示前面至少有两个在第二个波峰的上坡上,k=6表示在第二个波峰的下坡上
注意峰值数的位数至少为3并且第一位非零。
代码:
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<algorithm>
#include<vector>
#include<map>
#include<stack>
#include<list>
#include<queue>
#define eps 1e-6
#define INF (1<<30)
#define PI acos(-1.0)
using namespace std;
#define ll unsigned __int64
int dp[30][15][7];
//状态0表示前面都是0,状态1表示第一个上坡后面不能下坡,2表示第一个上坡后面可以是下坡,3表示第一个下坡
// 4 二 5 二 6 二
int aa[30],bb[30];
int dfs(int cur,int last,int flag,int aflag,int bflag)
{
if(!cur) //到了最后一位
return (flag==6)?0:-1;
if(!aflag&&!bflag&&dp[cur][last][flag]!=-1)
return dp[cur][last][flag];
int Min=aflag?aa[cur]:0; //下界
int Max=bflag?bb[cur]:9; //上界
int res=-1;
for(int i=Min;i<=Max;i++)
{
int status=0;
if(flag==0&&i)
status=1;
else if(flag==1)
{
if(i>last)
status=2;
else
status=-1;
}
else if(flag==2)
{
if(i<last)
status=3;
else if(i==last)
status=-1;
else
status=2;
}
else if(flag==3)
{
if(i>last)
status=4;
else if(i==last)
{
if(i)
status=4;
else
status=-1;
}
else
status=3;
}
else if(flag==4)
{
if(i>last)
status=5;
else
status=-1;
}
else if(flag==5)
{
if(i<last)
status=6;
else if(i==last)
status=-1;
else
status=5;
}
else if(flag==6)
{
if(i<last)
status=6;
else
status=-1;
}
if(status!=-1)
{
int temp=dfs(cur-1,i,status,aflag&&i==Min,bflag&&i==Max);
if(temp!=-1)
res=max(res,i+temp);
}
}
if(!aflag&&!bflag)
dp[cur][last][flag]=res;
return res;
}
int main()
{
int t;
scanf("%d",&t);
memset(dp,-1,sizeof(dp));
for(int ca=1;ca<=t;ca++)
{
ll a,b;
scanf("%I64u%I64u",&a,&b);
int pos=0;
while(b)
{
++pos;
aa[pos]=a%10;
a/=10;
bb[pos]=b%10;
b/=10;
}
int ans=dfs(pos,0,0,1,1);
printf("Case %d: ",ca);
if(ans!=-1)
printf("%d\n",ans);
else
printf("0\n");
}
return 0;
}