FZU -2109 Mountain Number(数位dp)

这有一颗山数                            [Submit

 Mountain Number

Accept: 433    Submit: 1086
Time Limit: 1000 mSec    Memory Limit : 32768 KB

 Problem Description

One integer number x is called "Mountain Number" if:

(1) x>0 and x is an integer;

(2) Assume x=a[0]a[1]...a[len-2]a[len-1](0≤a[i]≤9, a[0] is positive). Any a[2i+1] is larger or equal to a[2i] and a[2i+2](if exists).

For example, 111, 132, 893, 7 are "Mountain Number" while 123, 10, 76889 are not "Mountain Number".

Now you are given L and R, how many "Mountain Number" can be found between L and R (inclusive) ?

 Input

The first line of the input contains an integer T (T≤100), indicating the number of test cases.

Then T cases, for any case, only two integers L and R (1≤L≤R≤1,000,000,000).

 Output

For each test case, output the number of "Mountain Number" between L and R in a single line.

 Sample Input

3

1 10

1 100

1 1000

 Sample Output

9

54

384

日常测试日常难受,今天测试的时候看了一眼,可能就只会这一道题,就在那做呀做,做呀做,旁边的大佬27分钟拿下了First Blood而我,研究了三个小时,WA了7次才得到了欣慰的Accepted,险些爆零,吓死我了,呜呜呜

那么到底什么是山数呢?根据题目的要求就是奇数位上的数字要比他两侧的数字大

一开始我的想法是dfs传参 保留一个数前面的数,和他前前面的数,根据奇数位还是偶数位来判断三个数之间的关系,可能是没写对或者根本就行不通,终于以失败告终

然后我又开一个二维dp数组,写的也是乱七八糟但是求出了第一个和第三个样例的答案,稍微一改之后又求出了第二个样例答案,然后写了两个dfs,开了两个数组,正好把样例过了,就在我提交的时候意识到两个数组是没有关系的,500ms可能过不去,果然给我TLE了。。。于是机智的我灵光一闪,意识到开一个三维数组不就完了吗?  机智个锤锤,人家20分钟就交上了,我摸了三个小时。。。

好了上面的都是废话,现在来说这个题,我们来开一个三维的dp数组

dp[pos][pre][flag]表示的是第pos位,前一位数字是pre,flag为1表示在奇数位,为0则表示在偶数位   出现的合法的山数的数量

核心代码都在这了,注意dfs每深入一次flag就要变化一下,就这这里的 !flag操作

int dfs(int pos,int pre,int flag, int limit){
	if(pos<0)return 1;
	if(!limit&&dp[pos][pre][flag]!=-1)
		return dp[pos][pre][flag];
	int res=0;
	int up=limit?a[pos]:9;
	for(int i=0;i<=up;i++){
		if(flag&&i>=pre)
			res+=dfs(pos-1,i,!flag,limit&&i==up);
		if(!flag&&i<=pre)
			res+=dfs(pos-1,i,!flag,limit&&i==up);
	}
	if(!limit)dp[pos][pre][flag]=res;
	return res;
}

还有就是在我们的solve函数中第一次传参的时候,pre要传至少比9要大的数字,这样才能保证第一位数字的小于等于pre,至少可以使得dfs能够进行下去,不然直接return了就没有任何意义了。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<string>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#define mem(a,b) memset(a,b,sizeof(a))
#define ll long long
using namespace std;
const int inf=0x3f3f3f3f;
const int mm=20;

int dp[mm][mm][2];
int a[mm];

int dfs(int pos,int pre,int flag, int limit){
	if(pos<0)return 1;
	if(!limit&&dp[pos][pre][flag]!=-1)
		return dp[pos][pre][flag];
	int res=0;
	int up=limit?a[pos]:9;
	for(int i=0;i<=up;i++){
		if(flag&&i>=pre)
			res+=dfs(pos-1,i,!flag,limit&&i==up);
		if(!flag&&i<=pre)
			res+=dfs(pos-1,i,!flag,limit&&i==up);
	}
	if(!limit)dp[pos][pre][flag]=res;
	return res;
}

int solve(int x){
	if(x==0)return 1;
	int cnt=0;
	while(x){
		a[cnt++]=x%10;
		x/=10;
	}
	return dfs(cnt-1,10,0,1);
} 

int main()
{
	int t;
	scanf("%d",&t);
	mem(dp,-1);
	while(t--){
		int x,y; 
		scanf("%d%d",&x,&y);
		int res=solve(y)-solve(x-1);
		printf("%d\n",res);
	}
	return 0;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值