Hdu 3555 Bomb (DP_数位DP)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3555


题目大意:如果某个数中含有49,那就叫2B数(原来好像不是这个,随便啦).问[0,n]里有几个2B数,n <=2^63 - 1


解题思路:数位DP,和Hdu 3652差不多,但我感觉这题更简单,因为记录的状态更少。这题我用两种方法写过了,其实说两种方法也就是记忆化搜索时传递的参数不一样,核心都是一样的。

     第一种:传递三个参数,pos,flag,limit,pos表示当前转移到第几位,flag有三个值(2,1,0)对应着(含有49,不含49但前位是4,前位不是4也不含49),limit表示是否有上限,比如n=1234,现在转移到12,如果下一位选3,那么再下一位就有上限,上限为4,如果不选3,那么下一位就没限制,最高位9,转移能保证转移到数比n小。这样dp数组时2维的。

    第二种:这种跑的略慢,但更好理解。传递四个参数,pos,pre,flag,limit,pos和flag的意义一样,pre表示前一位是什么,flag表示是否含49,转移dp数组时3维的。


测试数据:

4
1
50
500


代码:

//第一种写法
#include <stdio.h>
#include <string.h>
#define MAX 1100
#define int64 __int64


int64 digit[30];
int64 dp[30][3],n;

int64 Dfs(int pos,int flag,int limit) {

	if (pos == -1) return flag == 2;
	if (!limit && dp[pos][flag] != -1)
		return dp[pos][flag];


	int64 sum = 0;
	int end = limit ? digit[pos] : 9;
	for (int i = 0; i <= end; ++i) {

		int have = flag;	//flag == 2 || (flag == 1 && i == 4)
		if (flag == 1 && i == 9) 
			have = 2;
		if (flag == 0 && i == 4) 
			have = 1;
		if (flag == 1 && i != 4 && i != 9)
			have = 0;
		//printf("pos %d flag %d have %d i %d sum %d\n",pos,flag,have,i,sum);
		sum += Dfs(pos-1,have,limit&&i==end);
		
	}


	if (!limit) dp[pos][flag] = sum;
	return sum;
}
int64 Cal(int64 n) {

	int pos = 0;
	while (n > 0) {

		digit[pos] = n % 10;
		n /= 10,pos++;
	}


	return Dfs(pos-1,0,1); 
}


int main()
{
	int i,j,k,t;


	scanf("%d",&t);
	while (t--) {

		scanf("%I64d",&n);
		memset(dp,-1,sizeof(dp));
		printf("%I64d\n",Cal(n));
	}
}
//第二种写法
#include <stdio.h>
#include <string.h>
#define MAX 1100
#define int64 __int64


int64 digit[30];
int64 dp[30][10][3],n;

int64 Dfs(int pos,int pre,int flag,int limit) {

	if (pos == -1) return flag == 1;
	if (!limit && dp[pos][pre][flag] != -1)
		return dp[pos][pre][flag];


	int64 sum = 0;
	int end = limit ? digit[pos] : 9;
	for (int i = 0; i <= end; ++i) {

		if (pre == 4 && i == 9)
			 sum += Dfs(pos-1,i,1,limit && end == i);
		else sum += Dfs(pos-1,i,flag,limit && end == i);
	}


	if (!limit) dp[pos][pre][flag] = sum;
	return sum;
}
int64 Cal(int64 n) {

	int pos = 0;
	while (n > 0) {

		digit[pos] = n % 10;
		n /= 10,pos++;
	}

	//printf("%d\n",pos);
	int64 ans = Dfs(pos-1,-1,0,1);
	return ans;
}


int main()
{
	int i,j,k,t;


	scanf("%d",&t);
	while (t--) {

		scanf("%I64d",&n);
		memset(dp,-1,sizeof(dp));
		printf("%I64d\n",Cal(n));
	}
}

本文ZeroClock原创,但可以转载,因为我们是兄弟。

你可能感兴趣的:(Hdu 3555 Bomb (DP_数位DP))