[折半枚举] Difference HDU - 5936

Difference

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 1467    Accepted Submission(s): 404


 

Problem Description

Little Ruins is playing a number game, first he chooses two positive integers y and K and calculates f(y,K), here

f(y,K)=∑z in every digits of yzK(f(233,2)=22+32+32=22)



then he gets the result

x=f(y,K)−y



As Ruins is forgetful, a few seconds later, he only remembers K, x and forgets y. please help him find how many y satisfy x=f(y,K)−y.

 

 

Input

First line contains an integer T, which indicates the number of test cases.

Every test case contains one line with two integers x, K.

Limits
1≤T≤100
0≤x≤109
1≤K≤9

 

 

Output

For every test case, you should output 'Case #x: y', where x indicates the case number and counts from 1 and y is the result.

 

 

Sample Input

 

2

2 2

3 2

 

 

Sample Output

 

Case #1: 1

Case #2: 2

 

 

Source

2016年中国大学生程序设计竞赛(杭州)

 

 

#include<bits/stdc++.h>
using namespace std;

const int mn = 100000;

long long po[10][10];
long long qian[mn + 50], hou[mn + 50];

int main()
{
	for (int i = 0; i <= 9; i++)
	{
		po[i][0] = 1;
		for (int j = 1; j <= 9; j++)
		{
			po[i][j] = po[i][j - 1] * i;
		}
	} // 计算 i 的 j 次方
	
	int T;
	scanf("%d", &T);
	for (int cas = 1; cas <= T; cas++)
	{
		int x, k;
		scanf("%d %d", &x, &k);
		
		/// y < 10 ^ 10 , 折半枚举
		/// 分别枚举左右部分 从 0 ~ 1e5 
		for (int i = 0; i < mn; i++)
		{
			int t = i;
			if (t % 10 == 0)
			{
				hou[i] = -i; // -y 
				while (t)
				{
					int q = t % 10;
					hou[i] += po[q][k];
					t /= 10;
				} // f(y, k)
			}
			else // 从末位为 0 递推
			{
				hou[i] = hou[i -1] - po[(i - 1) % 10][k] + po[i % 10][k] - 1;
			}
			qian[i] = hou[i] + i - (long long)i * mn;
			// 前半部分 f(y, k) 不变, + 计算 hou 时减去的 y
			// 前半部分后有5个0, 故 - mn * y;
		}
		
		// x == qian + hou
		/// 分别从小到大排序 总和不变 双指针遍历
		sort(qian, qian + mn);
		sort(hou, hou + mn);
		
		long long ans = 0;
		int r = mn - 1;
		for (int l = 0; l < mn; l++)
		{
			while (r >= 0 && qian[l] + hou[r] > x)
				r--;
			if (r >= 0 && l < mn && qian[l] + hou[r] == x)
			{
				long long temp1 = 1, temp2 = 1;
				while (l < mn - 1 && qian[l] == qian[l + 1])
				{
					l++, temp1++;
				} // 统计相同数字的数量
				while (r > 0 && hou[r] == hou[r - 1])
				{
					r--, temp2++;
				}
				ans += temp1 * temp2;
			}
		}
		printf("Case #%d: %lld\n", cas, ans - (x == 0));
		// x == 0 时 y 可能 == 0 要求 y > 0 , -1
	}
	
	
	return 0;
}



 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值