【HDU】5936 Difference 折半枚举
题意
定义函数\(f(y,k)=\sum_{i 是y的每一位}i^k\),比如\(f(232,2)=2^2+3^2+2^2==22\)。
\[x=f(y,k)-y
\]
现在给出 x 和 k,问有多少个 y 满足上述式子。
思路
刚做了HDU 5735 ,有点经验了。
对于一个整数 y,我们分为前 5 位和后 5 位。
那么
\[\begin{aligned}
&f(y,k)-y\\
&=(f(a,k)+f(b,k))-(a*100000+b)\\
&=(f(a,k)-a*100000)+(f(b,k)-b)\\
\end{aligned}
\]
那么我们可以求出上面两个括号内的所有值。
然后枚举其中一个值,二分另一个值。
注意 y 的值大于0,所以两个式子不能同时为0,其实也就是特判一下 x==0的时候。
代码
/*
* @Autor: valk
* @Date: 2020-08-11 12:38:37
* @LastEditTime: 2020-10-09 10:16:49
* @Description: 如果邪恶 是华丽残酷的乐章 它的终场 我会亲手写上 晨曦的光 风干最后一行忧伤 黑色的墨 染上安详
*/
#include <algorithm>
#include <iostream>
#include <map>
#include <math.h>
#include <queue>
#include <set>
#include <stack>
#include <stdio.h>
#include <string.h>
#include <string>
#include <vector>
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int mod = 1e9 + 7;
const int seed = 12289;
const double eps = 1e-6;
const int inf = 0x3f3f3f3f;
const int N = 1e5 + 10;
//
vector<ll> vec1, vec2;
ll qpow(ll a, ll b)
{
ll ans = 1;
while (b) {
if (b % 2)
ans *= a;
a *= a;
b /= 2;
}
return ans;
}
int main()
{
ll T, cas = 0;
scanf("%lld", &T);
while (T--) {
vec1.clear(), vec2.clear();
ll x, k;
scanf("%lld%lld", &x, &k);
for (ll i = 0; i <= 99999; i++) {
ll temp = i;
ll sum1 = 0;
while (temp) {
sum1 += qpow(temp % 10, k);
temp /= 10;
}
vec1.pb(sum1 - i), vec2.pb(sum1 - i * 100000);
}
sort(vec2.begin(), vec2.end());
ll ans = 0;
for (ll i = 0; i < vec1.size(); i++) {
ll l = lower_bound(vec2.begin(), vec2.end(), x - vec1[i]) - vec2.begin();
ll r = upper_bound(vec2.begin(), vec2.end(), x - vec1[i]) - vec2.begin();
ans += r - l;
}
if(x==0){
ans--;
}
printf("Case #%lld: %lld\n", ++cas, ans);
}
return 0;
}