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;
}
posted @ 2020-06-16 22:11  _kangkang  阅读(170)  评论(0编辑  收藏  举报