HDU 5936 Difference(思维+二分)——2016年中国大学生程序设计竞赛(杭州)

传送门

Little Ruins is playing a number game, first he chooses two positive integers y and K and calculates f(y,K) , here

f(y,K)=z in every digits of yzK(f(233,2)=22+32+32=22)


then he gets the result

x=f(y,K)y


As Ruins is forgetful, a few seconds later, he only remembers K , x and forgets y . please help him find how many y satisfy x=f(y,K)y .
 

Input
First line contains an integer T , which indicates the number of test cases.

Every test case contains one line with two integers x, K .

Limits
1T100
0x109
1K9
 

Output
For every test case, you should output ’Case #x: y’, where x indicates the case number and counts from 1 and y is the result.
 

Sample Input
  
  
2 2 2 3 2

题目大意:

已知一个函数 f(y,k)y=x ,其中 f(y,k) 表示 y 的每一位的 k 次方的和,其中已知 x,k 求有多少个 y

解题思路:

因为有一个很重要的条件就是 x0,那么 y 不会很大,因为 k 最大为 9 ,所以当 y>1010 时, f(y,k)y0 ,那么就将 y 缩小到 [1,1010],然后我们发现这样数据范围还是很大,那么我们考虑枚举前 5 位数字,然后在二分 [1,105],这样复杂度就不是很高了,首先我们预处理 g[i][j]: i  j  。然后枚举前 5 位,将其乘以 105, 然后加上 [1,105] 之间的数看是否为答案,会发现我们将其 i[1,105] 区间中的 f(i,k)i 先存起来,然后二分求解就OK了。

trick:
用 map 记录超时了,所以直接 upper_boundlower_bound 就OK了

代码:

#include <iostream>
#include <string.h>
#include <string>
#include <algorithm>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#include <map>
using namespace std;
typedef long long LL;
const int MAXN = 1e5+5;
const double PI = acos(-1);
const double eps = 1e-8;
const LL MOD = 1e9+7;
LL f[10][10], g[MAXN][10];
LL cal(LL y, int k){
    LL ans = 0;
    while(y){
        ans += f[y%10][k];
        y /= 10;
    }
    return ans;
}
void Init1(){
    for(int i=1; i<=9; i++){
        for(int j=0; j<10; j++){
            f[j][i] = j;
            for(int k=2; k<=i; k++) f[j][i] *= j;
        }
    }
}
void Init(){
    Init1();
    for(int i=1; i<=9; i++) for(int j=1; j<=100000; j++) g[j][i] = cal(j, i);
}
LL a[MAXN];
int main(){
    //freopen("C:/Users/yaonie/Desktop/in.txt", "r", stdin);
    //freopen("C:/Users/yaonie/Desktop/out.txt", "w", stdout);
    Init();
    int T; scanf("%d",&T);
    for(int cas=1; cas<=T; cas++){
        LL x; int k; scanf("%lld%d",&x,&k);
        LL ans = 0;
        for(int i=1; i<=100000; i++) a[i] = g[i][k]-i;
        sort(a+1, a+100001);
        for(LL i=0; i<=100000; i++){
            LL tmp = g[i][k]-i*100000;
            tmp = x-tmp;
            ans += upper_bound(a+1, a+100001, tmp)-lower_bound(a+1, a+100001, tmp);
        }
        printf("Case #%d: %lld\n",cas,ans);
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值