HDU 3271 SNIBB [数位DP]

  求从L~R转换成B进制之后数位之和为M的数有多少个。  

  国家集训队09年的论文《浅谈数位类统计问题》对这一类的问题总结的比较详细,数形结合的思想十分巧妙。

  第二种查询要用到第一种查询的结果,然后二分一下就可以了。

  

 1 #include <string.h>
 2 #include <stdio.h>
 3 #include <string.h>
 4 typedef long long LL;
 5 int q,x,y,b,m,k;
 6 int d[32][301],num[32];
 7 int dp(int l,int s){
 8     if(s<0)return 0;
 9     if(l==-1)return s==0;
10     if(d[l][s]!=-1)return d[l][s];
11     d[l][s]=0;
12     for(int i=0;i<b;i++)
13         d[l][s]+=dp(l-1,s-i);
14     return d[l][s];
15 }
16 int getsum(int x){
17     if(x<0)return 0;
18     int len=0,ans=0,kk=m;
19     while(x)num[len++]=x%b,x/=b;
20     for(int i=len-1;i>=0;i--){
21         for(int j=num[i];j>0;j--){
22             ans+=dp(i-1,kk),kk--;
23         }
24     }
25     return ans+(kk==0);
26 }
27 int main(){
28     int cas=0;
29     while(scanf("%d%d%d%d%d",&q,&x,&y,&b,&m)!=EOF){
30         if(x>y)x^=y^=x^=y;
31         memset(d,-1,sizeof d);
32         int lt=getsum(x-1),rt=getsum(y);
33         printf("Case %d:\n",++cas);
34         if(q==1)printf("%d\n",rt-lt);
35         else{
36             scanf("%d",&k);
37             if(rt-lt<k){
38                 printf("Could not find the Number!\n");
39                 continue;
40             }
41             int min=x-1,max=y,mid=((LL)min+max)>>1;
42             for(;min!=mid;mid=((LL)min+max)>>1){
43                 if(getsum(mid)-lt<k)min=mid;
44                 else max=mid;
45             }
46             printf("%d\n",mid+1);
47         }
48 
49     }
50     return 0;
51 }

  

原文地址:https://www.cnblogs.com/swm8023/p/2683346.html