题目链接:HDOJ3565

题意:首先定义了一个peak number,是没有前导0的,存在某一个数位,比左右两边的数字都大的数

然后Bi-peak number,是两个peak number的数位相连


分析样例就能够得到这个题的坑点,很友善的题

样例1是只有5个数位,要分成Bi-peak number,至少要6位,abcdef,其中b>a,b>c,e>d,e>f

样例2是想要分解的话,后面那个数有前导0

样例3简单


这个题充分的体现了自己数位DP不熟练

不会根据题目,来灵活的设计DP状态和转移


dp【pos】【state】【pre】是设计的状态

pos和pre很好理解,那么state如何定义呢?

因为是Bi-peak,所以需要标记我当前找的这个数处在那个阶段,是往第一个peak走,还是从第二个peak下来,都需要记录

所以:

0表示前导0

1表示第一个上升坡

2表示第一个顶点

3表示第一个下降坡

4表示第二个上升坡

5表示第二个顶点

6表示第二个下降坡


这个题是求最大值,不是求区间个数

所以不会满足区间的减法

所以用到一个新的技巧,把【X,Y】区间中的两端X,Y都数位分解放到dfs中去

记录两个变量,分别是前导的0和后置的flag

每次在数位枚举的时候,从可用的最小枚举到可用的最大


状态转移只能严格的从前一个转到后一个,因为必须按照数位的大小来排

特殊情况就是可以浪费如:123212321

可以上坡下坡时间长一点,数位多一点,这就是在山上多一个判断

细节见代码


#include<map>
#include<set>
#include<math.h>
#include<time.h>
#include<iostream>
#include<cstdio>
#include<queue>
#include<stack>
#include<stdio.h>
#include<cstring>
#include<string.h>
#include<algorithm>
#include<cstdlib>
using namespace std;

#define lson rt<<1,l,mid
#define rson rt<<1|1,mid+1,r
#define ll rt<<1
#define rr rt<<1|1
#define LL long long
#define ULL unsigned long long
#define maxn 1050
#define maxnum 1000050
#define eps 1e-6
#define input freopen("input.txt","r",stdin)
#define output freopen("output.txt","w",stdout)
#define MOD 1000000007

bool vis[25][10][15];
int dp[25][10][15];
int digitlow[25],digitup[25];

int dfs(int pos,int state,int pre,bool lowbound,bool upbound){
	if (state==0&&pos<6) return -1;
	if (pos==0) return state==5?0:-1;
	if (lowbound&&upbound&&vis[pos][state][pre])
		return dp[pos][state][pre];
	int Min=lowbound?0:digitlow[pos];
	int Max=upbound?9:digitup[pos];
	int ret=-1,temp;
	for(int i=Min;i<=Max;i++)
		switch(state){
			case 0:temp=dfs(pos-1,(i==0?0:1),i,lowbound||i>Min,upbound||i<Max);
			if (temp!=-1)
				ret=max(ret,temp+i);
			break;
			case 1:
			if (i>pre){
				temp=dfs(pos-1,1,i,lowbound||i>Min,upbound||i<Max);
				if (temp!=-1)
					ret=max(ret,temp+i);
				temp=dfs(pos-1,2,i,lowbound||i>Min,upbound||i<Max);
				if (temp!=-1)
					ret=max(ret,temp+i);
			}
			break;
			case 2:
			if (i<pre){
				temp=dfs(pos-1,3,i,lowbound||i>Min,upbound||i<Max);
				if (temp!=-1)
					ret=max(ret,temp+i);
			}
			break;
			case 3:
			if (i<pre){
				temp=dfs(pos-1,3,i,lowbound||i>Min,upbound||i<Max);
				if (temp!=-1)
					ret=max(ret,temp+i);
			}
			if (i){
				temp=dfs(pos-1,4,i,lowbound||i>Min,upbound||i<Max);
				if (temp!=-1)
					ret=max(ret,temp+i);
			}
			break;
			case 4:
			if (i>pre){
				temp=dfs(pos-1,4,i,lowbound||i>Min,upbound||i<Max);
				if (temp!=-1)
					ret=max(ret,temp+i);
				temp=dfs(pos-1,5,i,lowbound||i>Min,upbound||i<Max);
				if (temp!=-1)
					ret=max(ret,temp+i);
			}
			break;
			case 5:
			if (i<pre){
				temp=dfs(pos-1,5,i,lowbound||i>Min,upbound||i<Max);
				if (temp!=-1)
					ret=max(ret,temp+i);
			}
			break;
		}
	if (lowbound&&upbound){
		vis[pos][state][pre]=true;
		dp[pos][state][pre]=ret;
	}
	return ret;
}

int calc(unsigned long long x,unsigned long long y){
	memset(digitlow,0,sizeof(digitlow));
	memset(digitup,0,sizeof(digitup));
	int len1=0,len2=0;
	while(x){
		digitlow[++len1]=x%10;
		x/=10;
	}
	while(y){
		digitup[++len2]=y%10;
		y/=10;
	}
	return dfs(len2,0,0,0,0);
}

int main(){
	//input;
	int T;
	unsigned long long x,y;
	scanf("%d",&T);
	for(int Case=1;Case<=T;Case++){
		scanf("%I64u%I64u",&x,&y);
		int ans=calc(x,y);
		printf("Case %d: %d\n",Case,ans==-1?0:ans);
	}
	return 0;
}