uva 11361 Investigating Div-Sum Property 数位dp

//		uva 11361 Investigating Div-Sum Property 数位dp
//
//	题目大意:
//
//		给你一个整数a和一个整数b,问在[a,b]范围内,有多少个自身被k整除并且
//		各位数之和也能被k整除.比如k = 7 ,322满足条件,因为332能被整除7,并
//		3 + 2 + 2 = 7 也能被7整除
//
//	解题思路:
//
//		求一个区间的题目,这类题目,往往可以转化为不超过x的f(x).则最后要求
//		的就是f(b) - f(a-1).如何确定这个f(x).设d(i,m1,m2)为不确定的数字有
//		i个,已经确定的位的数子之和对k的余数对于k来说还需要m1才能凑成0,已经
//		确定的位的数值大小对于k的余数对k来说还需要m2才能凑成0的满足要求的个数
//		则d(i,m1,m2) = sigma(d(i-1,((m1-x)%k+k)%k,((m2 - x * 10^(i-1))%k+k))
//		{0<=k<=9},逐位求解.最后求和.采用记忆话搜索的方式.非常经典并且状态十分
//		完美的题目.
//
//	感悟:
//
//		这是在训练指南上看到的题目,开始看的时候,被k<=10000给吓到了.搞不了啊.这里
//		就要批评一下自己啦,要认真分析题目,不要被题目给的数据吓到了.认真分析啊!!!
//		看书上的分段求解还是云里雾里的.与传说中的数位dp有点类似.没想到还真是0.0
//		顺着书往下看,发现书上定义的状态十分的让人赞不绝口.不是我这等菜鸟所能想到的
//		状态.状态有了,dp的转移倒不是很难理解,实现起来对于我来说还是有点困难,因为
//		比较难掌控一些细节.整体的格局也不是很清楚.看了看大神们的优美代码,发现
//		记忆化搜索还是更好理解一些.虽然可能会慢一点,但重在好理解不是嘛.
//
//		初步接触数位dp,虽然知道是逐位进行,但是状态不是很好想.
//		不说什么啦,继续加油~~~FIGHTING

#include <cstdio>
#include <algorithm>
#include <cstring>
#include <iostream>

using namespace std;

typedef long long ll;

int x,y,k;
int a[15];
int vis[15][105][105];
ll d[15][105][105];
ll pow[15] = {1,10,100,1000,10000,100000,1000000,10000000,100000000,1000000000};

ll dp(int cnt,int m1,int m2){
	if (cnt==0)
		return (m1==0 && m2==0)?1:0;
	if (vis[cnt][m1][m2])
		return d[cnt][m1][m2];
	vis[cnt][m1][m2] = 1;
	ll& ans = d[cnt][m1][m2];
	for (int j=0;j<10;j++){
		ans += dp(cnt-1,((m1-j)%k+k)%k,((m2 - j * pow[cnt-1])%k+k)%k);
	}
	return ans;
}

ll solve(int n){
	int cnt = 0;
	while(n){
		a[cnt++] = n%10;
		n/=10;
	}
	ll ans = 0;
	memset(vis,0,sizeof(vis));
	memset(d,0,sizeof(d));
	int m1=0,m2=0;
	for (int i = cnt-1;i>=0;i--){
		for (int j=0;j<a[i];j++){	//注意,我们求的解不包括n本身
			ans += dp(i,(k-(m1+j)%k+k)%k,(k-(m2+j*pow[i])%k+k)%k);
		}
		m1 = (m1 + a[i])%k;
		m2 = (m2 + (pow[i] * a[i])%k)%k;
	}
	return ans;
}

void input(){
	scanf("%d%d%d",&x,&y,&k);
	if (k>=100){
		puts("0");
		return ;
	}

	printf("%lld\n",solve(y+1) - solve(x));
}

int main(){
	int t;
//	freopen("1.txt","r",stdin);
	scanf("%d",&t);
	while(t--){
		input();
	}
	return 0;
}

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-12-19 15:04:10

uva 11361 Investigating Div-Sum Property 数位dp的相关文章

UVA 11361 - Investigating Div-Sum Property(数位DP)

题目链接:11361 - Investigating Div-Sum Property 白书上的例题,不过没有代码,正好前几天写了一题数位DP的题目,这题也就相对轻松了. dp[i][x][y]表示加到第i位,数字 % k,数位和 % k的组合情况数,那么现在要添加一个0 - 9的数字上去状态转移为 dp[i + 1][(x * 10 + num) % k][(y + num) % k],计算总和后,由于数字本身不能超过最大值,所以最后还要添加上恰好前几位都为最大值的情况.然后最后在判断一下该数

uva 1489 - Math teacher&#39;s homework(数位dp)

题目链接:uva 1489 - Math teacher's homework 题目大意:给定n,k,以及序列m1,m2,-,mn, 要求找到一个长度为n的序列,满足0<=xi<=mi, 并且x1XORx2XOR-XORxn=k 解题思路:数位dp,在网上看了别人的代码,高大上... 假设有二进制数 k : 00001xxxx mi:0001xxxxx, 那么对于xi即可以满足任意的x1XORx2XOR-XORxi?1XORxi+1XOR-XORxn,根据这一点进行数位dp. dp[i][j]

UVA - 11038 How Many O&#39;s? (数位dp)

How Many O's? 题意是求区间内数字中0的个数,比如100就有两个0. 数位dp吧,dp[i][j][k], i很明显表示当前位置,j表示找到的0的个数,k表示要找的0的个数.因为数字里0的个数最多32个,所以可以枚举32种k的情况,用数位dp去找. #include <cstdio> #include <cstring> #include <algorithm> #include <iostream> using namespace std; #

ACdreamOJ 1154 Lowbit Sum (数位dp)

ACdreamOJ 1154 Lowbit Sum (数位dp) ACM 题目地址:ACdreamOJ 1154 题意: long long ans = 0; for(int i = 1; i <= n; i ++) ans += lowbit(i) lowbit(i)的意思是将i转化成二进制数之后,只保留最低位的1及其后面的0,截断前面的内容,然后再转成10进制数.即lowbit(i) = i&(-i). 每输入一个n,求ans 分析: 用二进制去考虑,可以发现这是个数位dp,如果当前第i

【数位dp】UVA - 11361 - Investigating Div-Sum Property

经典数位dp!而且这好像是数位dp的套路板子--不需要讨论原来我很头疼的一些边界. 改天用这个板子重做一下原来的一些数位dp题目. http://blog.csdn.net/the_useless/article/details/53674906 题目大意: 给定a,b,k三个正整数,统计在[a,b]之间的整数n中,有多少n自身是k的倍数,且n的各个数字(十进制)之和也是k的倍数.(1?a?b?231) 题目分析: 这是一道典型的数位DP题. n非常大,若是直接枚举的话会超时,考虑利用加法原理计

UVA 12063 Zeros and Ones (数位dp)

Binary numbers and their pattern of bits are always very interesting to computer programmers. In this problem you need to count the number of positive binary numbers that have the following properties: The numbers are exactly N bits wide and they hav

Codeforces Round #157 (Div. 1)B 数位dp

//枚举有几个(7或4),用数位dp的记忆化搜索找有i个(7或4)的数又多少个 //暴力搜索在第i个中选几个 #include<cstdio> #include<cstring> #include<iostream> using namespace std ; const int mod = 1e9 + 7; int dp[20][20];//第i位有 j个数(7或者4) int bit[20] ; int temp[20]; int luck[20]; int dfs

CodeForces - 1073E :Segment Sum (数位DP)

You are given two integers l l and r r (l≤r l≤r ). Your task is to calculate the sum of numbers from l l to r r (including l l and r r ) such that each number contains at most k k different digits, and print this sum modulo 998244353 998244353 . For

UVA - 10891 Game of Sum (区间dp)

题意:AB两人分别拿一列n个数字,只能从左端或右端拿,不能同时从两端拿,可拿一个或多个,问在两人尽可能多拿的情况下,A最多比B多拿多少. 分析: 1.枚举先手拿的分界线,要么从左端拿,要么从右端拿,比较得最优解. 2.dp(i, j)---在区间(i, j)中A最多比B多拿多少. 3.tmp -= dfs(i + 1, r);//A拿了区间(l, i),B在剩下区间里尽可能拿最优 tmp是A拿的,dfs(i + 1, r)是B比A多拿的,假设dfs(i + 1, r)=y-x,y是B拿的,x是A