HDU5936折半枚举+思维

来源:互联网 发布:怎么写销售数据分析表? 编辑:程序博客网 时间:2024/06/10 07:32

因为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;}


原创粉丝点击