您的位置:首页 > 其它

ural1057 Amount of Degrees 数位dp

2016-01-27 14:12 281 查看
题目大意:求给定区间[X,Y]中满足下列条件的整数个数:这个数恰好等于K个互不相等的B的整数次幂之和。

题解:

数位统计类问题可以看论文 《浅谈数位类统计问题》

转化成求[0,x]满足下列条件的整数个数:这个数恰好等于K个互不相等的B的整数次幂之和。二进制和k进制情况类似,所以只考虑二进制。ans=ans[0,y]-ans[0,x-1];

这里,我使用一棵完全二叉树来代表一个区间内的数。

例如右图中高度为4 的完全二叉树就可以 代表所有长度为4 的二进制数。

其范围为[0,2^4-1] 每个叶子就代表了 一个数。



很容易递推求出这个问题:

设f[h,s]表示在高度为h的完全二叉树包含的数中(范围是[0,2h-1]),二进制中恰含s个1的数有多少。

f[h,s] = f[h-1,s] + f[h-1,s-1];

这些事预处理出来的 也就是说 就算你只求[0,13],[0,16]的答案你也是算出来了的。

就下来就是查看你每次需要return的答案

每次”试探”着到没到限制 具体yy即可

个人感觉 数位dp 有两种写法

一种是预处理出所有答案 然后依次累加

另一种是记忆化搜索 如下一篇的某题

记忆化搜索比较无脑 像是从暴力搞过来的= =详见bzoj1026

#include<iostream>
#include<cstdio>
using namespace std;
const int N=100;
int f

,bit
;
int x,y,k,b;
void init(){
scanf("%d%d%d%d",&x,&y,&k,&b);
f[0][0]=1;
for(int i=1;i<32;i++)
for(int j=1;j<=i;j++){
f[i][0]=f[i-1][0];
f[i][j]=f[i-1][j]+f[i-1][j-1];
}
}
int calc(int x,int k,int b){
int t=x,len=0,tot1=0,tot2=0,ret=0;
while(t){
len++;
bit[len]=t%b;
if(bit[len]==1) tot1++;
if(bit[len]==0) tot2++;
t/=b;
}
if(tot1==k && tot1+tot2==len) ret++;
int tot=0;
for(int i=len;i;i--){
if(bit[i]>1){
ret+=f[i][k-tot];
break;
}
else if(bit[i]==1){
ret+=f[i-1][k-tot];
if(k<=tot) break;
tot++;
}
}
return ret;
}
int main(){
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
init();
printf("%d\n",calc(y,k,b)-calc(x-1,k,b));
printf("%d\n",calc(y,k,b));
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: