【数位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非常大,若是直接枚举的话会超时,考虑利用加法原理计算方案数. 
将数拆分开来,拆成一位一位的,从前往后枚举.那么就会出现形如”32**”这样枚举了部分,还有部分未枚举.可以用三维状态来表示:f(d,m1,m2)表示当前还有d个数未枚举,m1表示前缀各数之和%k,m2表示组成数%k.如之前的数”32**”就应该对应为f(2,5%k,3200%k). 
对应的转移方程则有

f(d,m1,m2)=∑f(d?1,(m1+i)%k,m2+i?10d?1%k|0?i?9)

所以dp数组需要开多大.10?10000?10000≈109?开不下! 
但是其实各个位数之和最大为1+9?9=82,所以当k>82时,直接输出0.

#include<cstdio>
#include<cstring>
using namespace std;
typedef long long ll;
int a,b,MOD,T;
int dp[15][90][90],pow_10[15];
int f(int d,int m1,int m2){
	if(dp[d][m1][m2]!=-1){
		return dp[d][m1][m2];
	}
	dp[d][m1][m2]=0;
	for(int i=0;i<10;i++){
		dp[d][m1][m2]+=f(d-1,(m1+i)%MOD,(m2+i*pow_10[d-1])%MOD);
	}
    return dp[d][m1][m2];
}
int calc(int x)
{
	int len=0;
	if(!x){
		len=1;
	}
	int t=x;
	while(t){
		++len;
		t/=10;
	}
    int res=0,LeftSide=0,SumDigits=0;//LeftSideê?μ±?°×ó±???£?SumDigitsê?μ±?°?ùóDêy????oí
    for(int i=1;i<=len;i++) {
        while((ll)LeftSide+(ll)pow_10[len-i]-1ll<=(ll)x){
        	//?D???ü·?′ó?aà??ìD?íù???ó£?òaê?2??üμ??°?íòaíùoóí?ò???
			//±èè?3212£????í2??ü′ó3200?ùíù3299?ó£???ó|??íùoóí?μ?íù3209?ó
            res+=f(len-i,SumDigits%MOD,LeftSide%MOD);
            LeftSide+=pow_10[len-i];
			++SumDigits;
        }
    }
    return res;
}
int main(){
//	freopen("uvaLive4123.in","r",stdin);
	scanf("%d",&T);
	pow_10[0]=1;
	for(int i=1;i<=9;++i){
		pow_10[i]=pow_10[i-1]*10;
	}
	for(;T;--T){
		scanf("%d%d%d",&a,&b,&MOD);
		if(MOD>82){
			puts("0");
			continue;
		}
		memset(dp,-1,sizeof(dp));
		for(int i=0;i<MOD;++i){
			for(int j=0;j<MOD;++j){
				dp[0][i][j]=0;
			}
		}
		dp[0][0][0]=1;
		printf("%d\n",calc(b)-calc(a-1));
	}
	return 0;
}
时间: 2024-10-17 12:19:58

【数位dp】UVA - 11361 - Investigating Div-Sum Property的相关文章

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).如

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 11361 Investigating Div-Sum Property

这道题居然提交了十次才过....期间小问题不断.思路的话基本是<训练指南>里面来的,不过有几个小问题需要注意一下.第一,当K在大于100的情况下,就直接输出0就可以了.因为a,b不超过2^31,可以估算出a,b最多十位十进制数,那么每位最大为9,所以各个数字之和是不可能超过100的,那么个数字之和为模K为0的条件是永远不可能到达的. 还有一点是,当剩余数字d=0时,当且仅当m1和m2都为0时,即f[0][0][0]为1,其余f[0][][]都为0.然后将已知的f[d][m1][m2]保存下来,

UVa 1009 Sharing Chocolate (数位dp)

题目链接: https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=3540 题目大意: 给一块长x,宽y的巧克力,和一个数组A={a1, a2, …,an},问能否经过若干次切分后,得到面积分别为a1,a2,…an的n块巧克力.每次切分只可以选择一块巧克力,将其分为两半,如下图,3×4的巧克力经过切分后,可以得到面积分别为6,3,2,1的巧克力.

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 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

uva 417 - Word Index(数位dp)

题目连接:uva 417 - Word Index 题目大意:按照题目中的要求,为字符串编号,现在给出字符串,问说编号为多少,注意字符串必须为递增的,否则编号为0. 解题思路:其实就是算说比给定字符串小并且满足递增的串由多少个.dp[i][j]表示第i个位为j满足比给定字符串小并且满足递增的串. dp[i][j]=∑k=0j?1dp[i?1][k]. 注意每次要处理边界的情况,并且最后要加上自身串.并且在处理边界的时候dp[i][0]要被赋值为1,代表前i个为空的情况. #include <cs

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

uva 10712 - Count the Numbers(数位dp)

题目链接:uva 10712 - Count the Numbers 题目大意:给出n,a,b:问说在a到b之间有多少个n. 解题思路:数位dp,dp[i][j][x][y]表示第i位为j的时候,x是否前面是相等的,y是否已经出现过n.对于n=0的情况要特殊处理前导0,写的非常乱,搓死. #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using na