hdu 4722 Good Numbers(初涉数位dp)

http://acm.hdu.edu.cn/showproblem.php?pid=4722

大致题意:若一个整数的各位数字之和是10的倍数,称这个数为"good number"。给出区间[A,B],求出该区间内"good number"的数的个数。

第一道数位dp,折腾了半天才明白怎么回事。

设dp[site][mod]表示到第site位(由高位向低位)前面各位数字之和对10取余为mod的数的个数,进行记忆化搜索。有两个很重要的点,首先是变量up,表示是否到达边界,up为0表示没到达,up为1表示到达边界,up的取值决定后面位数上的数的取值范围,是0-9还是0-dig[site]。然后是记忆化的条件,dp[site][mod]记录的是没到达边界的情况,相当于共用的结果,这也应该的记忆化的本质,而对于到达边界的,就没必要记忆化了。

#include <stdio.h>
#include <iostream>
#include <map>
#include <stack>
#include <vector>
#include <math.h>
#include <string.h>
#include <queue>
#include <string>
#include <stdlib.h>
#include <algorithm>
#define LL long long
#define _LL __int64
#define eps 1e-8
#define PI acos(-1.0)
using namespace std;

_LL dp[25][12];
int dig[25];

_LL dfs(int site, int mod, int up)
{
	if(site == 0)
		return mod == 0 ? 1 : 0; //边界。

	if(!up && dp[site][mod] != -1) //注意记忆化的条件,up = 0 且 dp[site][mod] != -1
		return dp[site][mod];

	int len = up ? dig[site] : 9; //根据是否到达上界确定第site位的取值
	_LL ans = 0;
	for(int i = 0; i <= len; i++)
	{
		ans += dfs(site-1, (mod+i)%10, up && (i == len) );
	}
	if(!up)
		dp[site][mod] = ans;
	return ans;
}

_LL cal(_LL x)
{
	int cnt = 0;
	_LL tmp = x;
	if(x < 0)
		return 0;

	while(tmp)
	{
		dig[++cnt] = tmp % 10;
		tmp /= 10;
	}
	memset(dp,-1,sizeof(dp));
	return dfs(cnt,0,1);
}

int main()
{
	int test;
	_LL x,y;
	scanf("%d",&test);

	for(int item = 1; item <= test; item++)
	{
		cin >> x >> y;
		memset(dp,-1,sizeof(dp));
		printf("Case #%d: %I64d\n",item,cal(y) - cal(x-1));
	}
	return 0;
}

hdu 4722 Good Numbers(初涉数位dp)

时间: 2024-07-29 14:19:34

hdu 4722 Good Numbers(初涉数位dp)的相关文章

HDU 4722 Good Numbers (数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4722 思路:数位dp,dp[i][j]表示到第i位,数字和%10为j,然后进行dp,注意完全匹配的情况是要+1,而其他情况是从0 到 9 都要考虑 代码: #include <stdio.h> #include <string.h> #include <algorithm> #include <iostream> using namespace std; int

hdu 4722 Good Numbers(dp)

public static void main(String[] args) { String a=null; if("aa".equals(a))//这种情形,不出现空指针异常 //if(a.equals("aa"))//出现空指针异常 { System.out.println(true); } else { System.out.println(false); } } 上面的两句不同的比较语句测试,第一句不出现空指针异常,第二句出现. 所以在变量和常量比较的时候

hdu 3709 Balanced Number (数位dp)

Balanced Number Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/65535 K (Java/Others) Total Submission(s): 1871    Accepted Submission(s): 836 Problem Description A balanced number is a non-negative integer that can be balanced if a pi

[hdu 4933]Miaomiao&#39;s Function 数位DP+大数

Miaomiao's Function Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 79    Accepted Submission(s): 18 Problem Description Firstly , Miaomiao define two functions f(x) , g(x): (K is the smallest

hdu 2089 不要62 (数位dp)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2089 思路:用变量记录吉利数,和最高位为2的吉利数还有不是吉利数的个数... code: #include<cstdio> #include<cstring> #include<algorithm> using namespace std; int dp[10][3]; //dp[i][j] ,i表示位数,j表示状态<pre name="code"

HDU 4352 XHXJ&#39;s LIS 数位DP + 状压

由LIS的nlogn解法 可以得出最后统计数组中数的个数即为LIS的长度 这样就可以状压了 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <c

LightOJ 1205 - Palindromic Numbers (数位dp)

LightOJ 1205 - Palindromic Numbers (数位dp) ACM 题目地址:SPOJ MYQ10 Mirror Number 题意: 求[a,b]中回文的个数. 分析: 是SPOJ MYQ01的简单版...其实有非递归方法的. 代码: /* * Author: illuz <iilluzen[at]gmail.com> * Blog: http://blog.csdn.net/hcbbt * File: 1205.cpp * Create Date: 2014-08-

HDU 4352 XHXJ&#39;s LIS 数位dp

题目链接:点击打开链接 题意: 一个数自身的最长子序列=每一位都是一个数字然后求的LIS 问区间内有多少个数 自身的最长子序列==k 思路: 因为自身的最长子序列至多=10,且由0~9组成,所以状压10个二进制表示0~9中哪些数字已经用过 dp[i][j] 表示长度为i的数字,最长子序列中出现的数字状态j的方法数.由于询问数=K,也存下来避免重复计算. #include <cstdio> #include <algorithm> #include <cstring> #

HDU 3709 Balanced Number 枚举+数位DP

枚举支点之后数位DP,注意姿势 #include <cstdio> #include <cstring> #include <cmath> #include <algorithm> #include <climits> #include <string> #include <iostream> #include <map> #include <cstdlib> #include <list&g