Pro4 数学游戏 (maga.pas/cpp/c)
题目描述:
小T又发脑残了,没错,她又要求奇怪的东西,这次她想知道[X,Y]之间整数有多少可以表示成K个不同的B的幂的和形势。如x,y,k,b=15,20,2,2,则有:
17=2^4+2^0
18=2^4+2^1
20=2^4+2^2 共3个符合要求的数
输入格式:
输入仅包含一行4个空格隔开的整数X,Y,K,B(1≤X≤Y≤2^31 -1,1≤K≤20)
输出格式:
输出文件包含一行一个即为所求合法数字个数。
样例输入:
15 20 2 2
样例输出:
3
这题题面本来是
因此dfs
就可以轻松过
然而暴力只有78%
幂次数使我们想到进制,问题就转化成了B进制下求位上总和为k的数
这显然可以用数位dp做
表示前i位,是否满,位和为k时的方案数,因为必须不同,所以每位只要枚举1和0
然后是模板
最后B=1要特判
//我比较喜欢用记搜
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int x,y,k,b;
int a[50],f[50][2][25];
int dfs(int ln,int p,int sum) {
if (sum>k) return 0;
if (ln==0) {
if (sum==k) return 1;
else return 0;
}
if (!p && f[ln][p][sum]!=-1) return f[ln][p][sum];
int cnt=0;
for (int i=0;i<=1;i++) {
if (p && i>a[ln]) continue;
int p1=p;
if (i<a[ln]) p1=0;
cnt+=dfs(ln-1,p1,sum+i);
}
if (!p) f[ln][p][sum]=cnt;
return cnt;
}
int chu(int x) {
memset(f,-1,sizeof f);
int cnt=0;
while (x) {
a[++cnt]=x%b;
x/=b;
}
return dfs(cnt,1,0);
}
int main() {
freopen("maga.in","r",stdin);
freopen("maga.out","w",stdout);
scanf("%d%d%d%d",&x,&y,&k,&b);
if (b==1) {
if (x<=1 && k==1) puts("1");
else puts("0");
return 0;
}
printf("%d\n",chu(y)-chu(x-1));
}