HDU5936折半枚举+思维

因为K只有10,如果x为999999999,F(x,k)也就才9^10,所以y的最大值不会很大,预计10^10,所以把这10位数,折半枚举一下,预处理左边5位,然后再枚举右边5位,这样时间复杂度就只会有n*logn(n=100000);问题得到解决。

至于x==0为什么要-1?

x = f(y,k) - y >= 0

-> f(y,k) >= y 

-> y > 0

-> x > f(y,k) >= y

所以y的长度不超过10位

y = a + b*(1e5)

x = f(a,k) - a + f(b,k) - b*(1e5)

x - f(a,k) + a = f(b,k) - b*(1e5)

那f(b,k) - b*(1e5) == (x - f(a,k) + a)的数量和就是答案

预处理出所有的 f(b,k) - b*(1e5)

枚举a,二分法找出满足f(b,k) - b*(1e5) == (x - f(a,k) + a)的数量和即可


当x==0时,因为y>0,a,b不能同时为0,所以答案要-1


#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int INF=0x3f3f3f3f;
ll f[12][12];
ll a[100010];
ll cnt[12][100010];
vector<ll>g[12];
ll solve(ll num,ll k)
{
    ll ans=0;
    while(num)
    {
        ans+=f[num%10][k];
        num/=10;
    }
    return ans;
}
void init()
{
    for(int i=0;i<=9;i++)
    {
        f[i][1]=i;
        for(int j=2;j<=9;j++)
            f[i][j]=f[i][j-1]*i;
    }
    for(int i=1;i<=9;i++)
    {
        for(ll num=0;num<100000;num++)
        {
            a[num]=solve(num,i)-num*100000;
        }
        sort(a,a+100000);
        int t=0;
        int xx=-1;
        while(t<100000)
        {
            if(t==0||a[t]!=a[t-1])
            {
                g[i].push_back(a[t]);
                cnt[i][++xx]++;
            }
            else
            {
                cnt[i][xx]++;
            }
            t++;
        }
    }
}
int main()
{
    init();
    int t;scanf("%d",&t);
    for(int v=1;v<=t;v++)
    {
        ll x,k;scanf("%lld%lld",&x,&k);
        ll ans=0;
        for(int i=0;i<100000;i++)
        {
            ll v=solve(i,k)-i;
            ll need=x-v;
            int pos=lower_bound(g[k].begin(),g[k].end(),need)-g[k].begin();
            if(pos<g[k].size()&&pos>=0&&g[k][pos]==need)
            {
                ans+=cnt[k][pos];
            }
        }
        if(x==0)
            ans--;
        printf("Case #%d: %lld\n",v,ans);
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值