Hdu 5936 Difference【思维+折半枚举+二分】

本文介绍了一个数值游戏的算法实现过程,通过分析特定数值X,探讨了如何找出所有符合条件的正整数y,使得F(y,K)-y=X成立。采用分段枚举与二分查找的方法,有效地解决了问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Difference

Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 977    Accepted Submission(s): 271


Problem Description
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 Kx 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 xK.

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
 

Sample Output
Case #1: 1 Case #2: 2

题目大意:


F(y,K)=Σ(y的各个位子上的数)^K;

然后我们可以得到一个值X=F(y,K)-y;

我们现在有一个值X,问有多少个正整数y使得其满足条件。


思路:


①首先观察到X的计算式子,X=F(y,K)-y;根据X的数据范围X>=0我们可以知道,y是不可以大于X的。

所以我们可以简单的认定,y最长可以达到10个长度。


②那么我们可以折半枚举,O(1e5)去枚举前五个长度的部分,O(1e5)去枚举后五个长度的部分。

我们知道,我们将数分成两部分并不影响结果的运算,前五个长度的部分对结果的贡献值为val-y*1e5;后五个长度的贡献值为val-y.

那么我们对应得到后五个长度部分的值之后,我们可以二分前五个长度合法的区间范围个数【L,R】,那么当前结果贡献的值就是R-L+1.


③值得注意的点是,y需要是正整数,y==0的情况不能存在,特判一下即可。


Ac代码:


#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define ll long long int
ll temp[1600000];
ll poww[15][25];
ll X,K,output;
int cnt;
void init()
{
    for(int i=0;i<=9;i++)
    {
        poww[i][0]=1;
        for(int j=1;j<=9;j++)
        {
            poww[i][j]=poww[i][j-1]*i;
        }
    }
}
void dfs(ll y,ll val,int dep)
{
    if(dep==5)
    {
        temp[cnt++]=val-y*100000;
        return ;
    }
    for(int i=0;i<=9;i++)
    {
        dfs(y*10+i,val+poww[i][K],dep+1);
    }
}
void Dfs(ll y,ll val,int dep)
{
    if(dep==5)
    {
        if(y==0)return ;
        int L=-1,R=-1;
        int l=0;
        int r=cnt-1;
        while(r-l>=0)
        {
            int mid=(l+r)/2;
            if(val-y+temp[mid]<X)
            {
                l=mid+1;
            }
            else if(val-y+temp[mid]>=X)
            {
                if(val-y+temp[mid]==X)
                {
                    L=mid;
                }
                r=mid-1;
            }
        }
        l=0;
        r=cnt-1;
        while(r-l>=0)
        {
            int mid=(l+r)/2;
            if(val-y+temp[mid]<=X)
            {
                if(val-y+temp[mid]==X)
                {
                    R=mid;
                }
                l=mid+1;
            }
            else if(val-y+temp[mid]>X)
            {
                r=mid-1;
            }
        }
        if(L==-1||R==-1)return ;
        output+=R-L+1;
        return ;
    }
    for(int i=0;i<=9;i++)
    {
        Dfs(y*10+i,val+poww[i][K],dep+1);
    }
}
int main()
{
    init();
    int kase=0;
    int t;scanf("%d",&t);
    while(t--)
    {
        cnt=0;
        output=0;
        scanf("%lld%lld",&X,&K);
        dfs(0,0,0);
        sort(temp,temp+cnt);
        Dfs(0,0,0);
        printf("Case #%d: ",++kase);
        printf("%lld\n",output);
    }
}













评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值