HDU-5936 Difference(折半枚举)
题目链接:HDU-5936 Difference
题意
有两个等式:
\[\begin{split}f(y,K)&=\sum_{z\ {\rm in\ every\ digits\ of}\ y}z^K \qquad \ \qquad (1)\\x&=f(y,K)-y \qquad\qquad\qquad\quad (2)\end{split}
\]
给定 \(x(0\leq x\leq 10^9)\) 和 \(K(1\leq K\leq 9)\) ,问有多少个不同的正整数 \(y\) 能满足以上两个等式。
思路
假如 \(y\) 是11位,那么 \(f(y,K)\) 的最大值为 \(f(99999999999, 9)=11\cdot 9^9\) ,只有10位,所以 \(x=f(y,K)-y<0\) ,当 \(y>11\) 位时显然也是这样,可得 \(y\) 最大只有10 位。
令 \(y=a+b\cdot 10^5\) ,则
$x=f(y,K)-y=f(a,K)+f(b,K)-a-b\cdot 10^5 $
\(\Longrightarrow x-f(a,K)+a=f(b,K)-b\cdot 10^5\) ,
即有多少对 \(\langle a,b\rangle\) 满足 \(x-f(a,K)+a=f(b,K)-b\cdot 10^5\) ,就有多少个 \(y\) 满足题目的等式。预处理所有的 \(f(b,K)-b\cdot 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\n", cas, ans);
}
return 0;
}
作者:_kangkang
本文版权归作者和博客园共有,欢迎转载,但必须给出原文链接,并保留此段声明,否则保留追究法律责任的权利。