HDU3271 SNIBB(数位dp+二分)

来源:互联网 发布:淘宝怎么拉黑店铺 编辑:程序博客网 时间:2024/06/06 08:25

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3271

题意:
有两种询问:
q=1,在[x,y]区间内,转换成b进制数,数位和为m的有多少个;
q=2,在[x,y]区间内,转换成b进制数,数位和是m的第k个数是多少(十进制)

源代码:

#include<cstdio>#include<cstring>#include<string>#include<queue>#include<map>#include<stack>#include<vector>#include<iostream>#include<algorithm>using namespace std;typedef __int64 LL;LL dp[35][305];//dp[i][j]表示长度为i数位和为j时的数的个数int num[35];int m,b;LL dfs(int len,int nowsum,bool limit){    if(len==0)        return nowsum==m;    if(!limit && dp[len][nowsum]!=-1)    {        return dp[len][nowsum];    }    int mmax=limit?num[len]:b-1;    __int64 ans=0;    for(int i=0; i<=mmax; i++)    {        ans+=dfs(len-1,nowsum+i,limit && i==mmax);    }    if(!limit)    {        dp[len][nowsum]=ans;    }    return ans;}LL solve(LL n){    if(n<=0)        return 0;    int cnt=0;    while(n)    {        num[++cnt]=n%b;        n/=b;    }    return dfs(cnt,0,true);}LL Search(LL l,LL r,LL k){    LL ans=-1;    LL x=l-1;    while(l<=r)    {        LL mid=(l+r)/2;        if(solve(mid)-solve(x-1)>=k)        {            ans=mid;            r=mid-1;        }        else l=mid+1;    }    return ans;}int main(){    int op;    LL x,y;    int cas=1;    while(~scanf("%d",&op))    {        memset(dp,-1,sizeof dp);        printf("Case %d:\n",cas++);        if(op==1)        {            scanf("%I64d%I64d%d%d",&x,&y,&b,&m);            if(x>y)                swap(x,y);            x--;            printf("%I64d\n",solve(y)-solve(x));        }        else if(op==2)        {            LL k;            scanf("%I64d%I64d%d%d%I64d",&x,&y,&b,&m,&k);            if(x>y)                swap(x,y);            LL ans=Search(x,y,k);            if(ans==-1)            {                puts("Could not find the Number!");            }            else            {                printf("%I64d\n",ans);            }        }    }    return 0;}
0 0