HDU-5936 Difference(折半枚举)
Posted kangkang-
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU-5936 Difference(折半枚举)相关的知识,希望对你有一定的参考价值。
题目链接:HDU-5936 Difference
题意
有两个等式:
给定 (x(0leq xleq 10^9)) 和 (K(1leq Kleq 9)) ,问有多少个不同的正整数 (y) 能满足以上两个等式。
思路
假如 (y) 是11位,那么 (f(y,K)) 的最大值为 (f(99999999999, 9)=11cdot 9^9) ,只有10位,所以 (x=f(y,K)-y<0) ,当 (y>11) 时显然也是这样,可得 (y) 最大只有10 位。
令 (y=a+bcdot 10^5) ,则
$x=f(y,K)-y=f(a,K)+f(b,K)-a-bcdot 10^5 $
(Longrightarrow x-f(a,K)+a=f(b,K)-bcdot 10^5) ,
即有多少对 (langle a,b angle) 满足 (x-f(a,K)+a=f(b,K)-bcdot 10^5) ,就有多少个 (y) 满足题目的等式。预处理所有的 (f(b,K)-bcdot 10^5) 的值,枚举左式的 (a) ,二分查找有多少个右式的值等于左式,将每次枚举查找到的数量相加就是答案。(x=0) 时,由于统计了 (y=0) 的情况,但是 (y) 只能为正整数,所以答案要减 1。
代码实现
#include <cstdio>
#include <algorithm>
using std::sort;
typedef long long LL;
LL g[10][100010], pw[10][10];
int fun(int x, int k) {
int res = 0;
while (x) {
res += pw[x%10][k];
x /= 10;
}
return res;
}
int main() {
for (int i = 1; i < 10; i++) {
int tmp = 1;
for (int j = 1; j < 10; j++) {
tmp *= i;
pw[i][j] = tmp;
}
}
for (int i = 1; i < 10; i++) {
for (int j = 0; j < 100000; j++) {
g[i][j] = fun(j, i) - 1ll * j * 100000;
}
sort(g[i], g[i] + 100000);
}
int T;
scanf("%d", &T);
for (int cas = 1; cas <= T; cas++) {
int x, K;
scanf("%d %d", &x, &K);
int ans = 0;
for (int i = 0; i < 100000; i++) {
LL left = x - fun(i, K) + i;
ans += std::upper_bound(g[K], g[K] + 100000, left) - std::lower_bound(g[K], g[K] + 100000, left);
}
if (x == 0) ans--;
printf("Case #%d: %d
", cas, ans);
}
return 0;
}
以上是关于HDU-5936 Difference(折半枚举)的主要内容,如果未能解决你的问题,请参考以下文章
HDU 5936 Difference 中途相遇法(中国大学生程序设计竞赛(杭州))
HDU 5936 Difference(思维+二分)——2016年中国大学生程序设计竞赛(杭州)