Investigating Div-Sum Property UVA11361

思路按照训练指南上说的的递推,table[i][j][k]表示i位数各位数字和对给定数取模为j,数字本身对给定数取模为k的数字个数,最后的统计细节需要注意,要从高位到低位统计,个位要单算。



#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <queue>
#include <algorithm>
#include <vector>
#include <cstring>
#include <stack>
#include <cctype>
#include <utility>   
#include <map>
#include <string>  
#include <climits> 
#include <set>
#include <string> 
#include <sstream>
#include <utility>   
#include <ctime>
 
using std::priority_queue;
using std::vector;
using std::swap;
using std::stack;
using std::sort;
using std::max;
using std::min;
using std::pair;
using std::map;
using std::string;
using std::cin;
using std::cout;
using std::set;
using std::queue;
using std::string;
using std::istringstream;
using std::make_pair;
using std::greater;
using std::endl;

const int MAXN(82);

int table[11][MAXN+10][MAXN+10];
int arr[11][MAXN+10][MAXN+10];

int count(int sour, int K)
{
	if(sour < 10)
		return sour/K;
	int weight = 1, mxb = 0;
	while(sour/weight >= 10)
	{
		weight *= 10;
		++mxb;
	}
	int b1 = 0, b2 = 0;
	int ret = 0;
	for(int i = mxb; i > 0; --i)
	{
		int temp = sour/weight;
		for(int j = 0; j < temp; ++j)
			ret += table[i-1][((K-j-b1)%K+K)%K][((K-j*weight-b2)%K+K)%K];
		b1 += temp;
		b2 += temp*weight;
		sour -= temp*weight;
		weight /= 10;
	}
	for(int i = 0; i <= sour; ++i)
		if(((K-i-b1)%K+K)%K == 0 && ((K-i-b2)%K+K)%K == 0)
			++ret;
	--ret;
	return ret;
}

int main()
{
	int T;
	scanf("%d", &T);
	while(T--)
	{	
		int A, B, K;
		scanf("%d%d%d", &A, &B, &K);
		if(K > MAXN)
		{
			printf("0\n");
			continue;
		}
		memset(table, 0, sizeof(table));
		int size = -1, tb = B;;
		while(tb)
		{
			++size;
			tb /= 10;
		}
		for(int i = 0; i <= 9; ++i)
			table[0][i%K][i%K] += 1;
		int weight = 1;
		for(int i = 1; i < size; ++i)
		{
			weight *= 10;
			for(int k1 = 0; k1 < K; ++k1)
				for(int k2 = 0; k2 < K; ++k2)
					for(int j = 0; j <= 9; ++j)
						table[i][(k1+j)%K][((j*weight+k2)%K+K)%K] += table[i-1][k1][k2];	
		}
		printf("%d\n", count(B, K)-count(A-1, K));
	}
	return 0;
}

有一个比较类似的问题求从0到n所有数中k( 0<=k<= 9)出现的次数,从0到11,1一共出现了4次,统计的方法为分别对每一位上k出现的次数统计,记得编程之美上有这道问题,当k=0时要注意把类似00,01,02,...,000,001......中0的个数减去,扩展后可以都到不同进制下,不同数字出现的个数


LL count(LL sour, LL goal, LL BASE) //原数, 数字k, 进制
{
	if(sour < 0)
		return 0LL;
	LL weight = 1LL, ts = 0LL;
	LL ret = 0LL;
	while(sour)
	{
		LL t1 = sour%BASE, t2 = sour/BASE;
		if(t1 > goal)
			++t2;
		else
			if(t1 == goal)
				ret += (ts+1);                        
		ret += weight*t2;
		if(!goal)
			ret -= weight;
		ts += t1*weight;
		sour /= BASE;
		weight *= BASE;
	}
	if(!goal)
		++ret;
	return ret;
}





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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值