1081. 度的数量

题目链接

1081. 度的数量

求给定区间 \([X,Y]\) 中满足下列条件的整数个数:这个数恰好等于 \(K\) 个互不相等的 \(B\) 的整数次幂之和。

例如,设 \(X = 15, Y = 20, K = 2, B = 2\),则有且仅有下列三个数满足题意:

\(17 = 2^4 + 2^0\)
\(18 = 2^4 + 2^1\)
\(20 = 2^4 + 2^2\)

输入格式

第一行包含两个整数 \(X\)\(Y\),接下来两行包含整数 \(K\)\(B\)

输出格式

只包含一个整数,表示满足条件的数的个数。

数据范围

\(1 \le X \le Y \le 2^{31}-1\),
\(1 \le K \le 20\),
\(2 \le B \le 10\)

输入样例:

15 20
2
2

输出样例:

3

解题思路

数位dp

显然,本题可以转化为前缀和计算贡献,即问题等价于计算 \(0\sim x\) 中满足条件的整数个数,不妨先将 \(x\)\(B\) 进制数表示出来,从最高位开始枚举位数 \(i\),由于受条件限制,每一位只能取或不取,如果当前最高位 \(i\) 大于 \(1\),则说明这 \(i\) 位数可以任取,即贡献为 \(C_i^k\),否则如果这位为 \(1\),则有两种选择:取这位或不取这位,记录前面已经取走 \(lst\)\(1\),如果当前这位不取,则后面的数可以任取,贡献为 \(C_{i-1}^{k-lst}\),注意,如果 \(k==lst\),说明此时已经全部取走,后面都不能再取了,此时也算作一种方案

  • 时间复杂度:\(O(30^2+logw)\)

代码

// Problem: 度的数量
// Contest: AcWing
// URL: https://www.acwing.com/problem/content/1083/
// Memory Limit: 64 MB
// Time Limit: 1000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// %%%Skyqwq
#include <bits/stdc++.h>
 
// #define int long long
#define help {cin.tie(NULL); cout.tie(NULL);}
#define pb push_back
#define fi first
#define se second
#define mkp make_pair
using namespace std;
 
typedef long long LL;
typedef pair<int, int> PII;
typedef pair<LL, LL> PLL;
 
template <typename T> bool chkMax(T &x, T y) { return (y > x) ? x = y, 1 : 0; }
template <typename T> bool chkMin(T &x, T y) { return (y < x) ? x = y, 1 : 0; }
 
template <typename T> void inline read(T &x) {
    int f = 1; x = 0; char s = getchar();
    while (s < '0' || s > '9') { if (s == '-') f = -1; s = getchar(); }
    while (s <= '9' && s >= '0') x = x * 10 + (s ^ 48), s = getchar();
    x *= f;
}

int x,y,k,b;
int C[35][35];
int a[35],n;
int get(int x,int y)
{
	n=0;
	do
	{
		a[++n]=x%y;
		x/=y;
	}while(x);
	int res=0,lst=0;
	for(int i=n;i;i--)
	{
		if(a[i]>1)
		{
			if(k>lst)
				res+=C[i][k-lst];
			break;
		}
		else if(a[i])
		{
			if(k>lst)
				res+=C[i-1][k-lst];
			lst++;	
		}
		if(lst==k)
		{
			res++;
			break;
		}
	}
	return res;
}
void init()
{
	for(int i=0;i<32;i++)
		for(int j=0;j<=i;j++)
			if(!j)C[i][j]=1;
			else
				C[i][j]=C[i-1][j-1]+C[i-1][j];
}
int main()
{
    scanf("%d%d%d%d",&x,&y,&k,&b);
    init();
    printf("%d",get(y,b)-get(x-1,b));
    return 0;
}
posted @ 2022-12-07 12:33  zyy2001  阅读(24)  评论(0编辑  收藏  举报