Amount of Degrees 数位DP

Posted 行码棋

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Amount of Degrees 数位DP相关的知识,希望对你有一定的参考价值。

题目链接

题目
求给定区间 [ X , Y ] [X,Y] [X,Y] 中满足下列条件的整数个数:这个数恰好等于 K K K 个互不相等的 B B B 的整数次幂之和。例如,设 X = 15 , Y = 20 , K = 2 , B = 2 X=15,Y=20,K=2,B=2 X=15,Y=20,K=2,B=2,则有且仅有下列三个数满足题意:

17 = 2 4 + 2 0 17=2^4+2^0 17=24+20
18 = 2 4 + 2 1 18=2^4+2^1 18=24+21
20 = 2 4 + 2 2 20=2^4+2^2 20=24+22

思路:
定义 d p ( n ) dp(n) dp(n)为小于等于 n n n的满足题目条件的数的个数

[ l , r ] [l,r] [l,r]区间内满足题意的数的个数为 d p ( r ) − d p ( l − 1 ) dp(r)-dp(l-1) dp(r)dp(l1),类似前缀和的思想

转化题意为:
求在目标区间内的数中化为B进制数中,数位中有K个1的个数。

初始化 i n i t init init是初始化组合数的,利用公式 C a b = C a − 1 b + C a − 1 b − 1 C_{a}^{b} = C_{a-1}^{b} + C_{a-1}^{b-1} Cab=Ca1b+Ca1b1初始化

last为前面已经选过的1的个数,res为总的个数

从最高位枚举每一位,如果当前位大于等于1,

  • 先加上当前位数为0的情况,即 C i K − l a s t C_i^{K-last} CiKlast,i表示后面剩余的位数,

  • 然后就可以加上当前位等于1的情况,即 C i K − l a s t − 1 C_i^{K-last-1} CiKlast1,当前位为1,所以要多减去1

  • 当前位等于1时要更新last

然后就是最后一位时进行特判,如果最后一位为0时,且之前的last=K,说明本身这个数也满足条件,需要加上去

#include<bits/stdc++.h>
using namespace std;
const int N = 35;

int f[N][N];
int K,B;

void init()
{
	for(int i=0;i<N;i++)
		for(int j=0;j<=i;j++)
			if(!j) f[i][j] = 1;
			else f[i][j] = f[i-1][j-1]+f[i-1][j];
}

int dp(int n)
{
	if(n==0) return 0;
	vector<int>nums;
	
	while(n) nums.push_back(n%B),n/=B;
	
	int res = 0,last = 0;
	for(int i=nums.size()-1;i>=0;i--)
	{
		int x = nums[i];
		if(x)
		{
			res += f[i][K-last];
			if(x>1)
			{
				if(K-last-1>=0)res += f[i][K-last-1];
				break;
			}
			else 
			{
				last++ ;
				if(last>K) break;
			}
		}
		if(!i && last==K) res++;
	}
	return res;
}
int  main()
{
	init();
	int l,r;
	cin>>l>>r>>K>>B;
	
	cout<<dp(r)-dp(l-1)<<'\\n';
	return 0;
}

以上是关于Amount of Degrees 数位DP的主要内容,如果未能解决你的问题,请参考以下文章