http://acm.hdu.edu.cn/showproblem.php?pid=5936
给出f(y,K)=∑z in every digits of yzK(f(233,2)=22+32+32=22)
问对于给定x和k,有几个y能让式子
x=f(y,K)−y成立。
y是正整数
0≤x≤109
0≤x≤109
1≤K≤9
这样如果要让式子成立,那f(y, k)就要大于y,对于一个固定的y,肯定k越大,这个式子越容易成立,所以假设k都取9,我们尝试寻找最大的y是多少
如果y有9位,比如999999999,f(y,9) = 9^9 * 9 = 9^10 > y。继续枚举y有10位,9999999999,f(y,9) = 9^9 * 10 = 9^10 + 9^9 < y,所以y不可能多于10位。
那这样暴力枚举y效率还是不够,观察式子发现,f(y,k)的值和y具体是多少没关系,只与y的组成有关系(每个数字有几个)有关系,暴力搜索发现,y的组成只有几百万种。
这样我们通过搜索枚举y的组成,算出f(y, k),减去已知的x得到一个y值,再判断一下这个y值的组成与我们枚举的组成是否相同,如果相同,那这就是一个合法的y。
//
// main.cpp
// 5936 Difference 搜索 (搜索 剪枝)
//
// Created by czf on 2016/11/21.
// Copyright © 2016年 czf. All rights reserved.
//
#include <cstdio>
#include <vector>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long LL;
LL fact[10][10], a[10], res, k, x; //a[]代表y的组成,a[i] = j表示i有j个。
void init() { //预处理次方
for (int i = 0; i < 10; i ++) fact[i][0] = 1;
for (int i = 0; i < 10; i ++) {
for (int j = 1; j < 10; j ++) {
fact[i][j] = fact[i][j-1] * i;
}
}
}
void dfs(int has, int pos) { //has表示接下来组成还能使用多少个数字,pos表示目前在枚举pos这个数字要用几次
if (has == 0 || pos > 9) { //接下来没有数字可以用了,或者9个数字已经枚举完了
LL sum = 0; //f(y, k)
for (int i = 1; i < 10; i ++) {
sum += fact[i][k] * a[i];
}
LL y = sum - x;
if (y <= 0) return;
LL b[10] = {0}; //算出来y值的组成
while (y) {
b[y%10] ++;
y /= 10;
}
for (int i = 0; i < 10; i ++) { //判断枚举y的组成和算出来y的组成是否相同
if (a[i] != b[i]) return;
}
res ++;
return;
}
for (int i = 0; i <= has; i ++) { //枚举pos这个数字有几个
a[pos] = i;
dfs(has - i, pos + 1);
}
}
int main() {
init();
int T, kase = 0; scanf("%d",&T);
while (T--) {
res = 0;
memset(a, 0, sizeof(a));
scanf("%lld%lld",&x,&k);
dfs(10, 0);
printf("Case #%d: %lld\n",++kase, res);
}
return 0;
}
等式
这个 问 d's等式
x
=
f
(
y
,
K
)
−
y,