(CF855E)Salazar Slytherin‘s Locket(数位DP)

题目链接:Problem - 855E - Codeforces

题意:就是给你一个l和r以及b,求在b进制下的数l<=k<=r满足0~b-1都出现偶数次的数有多少个

这显然是一道数位DP,其实这道题我一开始理解错题意了,出现偶数次按道理说应该是出现过的,没出现过应该是不符合题意的,而这道题却将正确答案包括了0~b-1种的一些数未出现的情况,这一点确实是题意表述不清了,因为我之前做过一道类似的题,求的是l到r内奇数位出现偶数次和偶数位出现奇数次的数,而那道题目中一定要出现才算,建议大家做一下那道题,还是挺好的一道题:(SPOJ - BALNUM)Balanced Numbers(数位DP+状态压缩)_AC__dream的博客-CSDN博客

最后想说的一点就是,假如f[i][j][表示遍历到第i位,出现次数状态为j的合法方案数,那么对于每次询问,由于b可能不同,所以按道理我们应该每次都初始化f数组,但是这样会超时,我们应该在f数组上加上一维表示进制的数,f[i][j][k]表示遍历到第i位,出现次数状态为j在k进制下的方案数,这样我们就只需要初始化一次f,且当询问到相同的进制时我们还能使用原来已经计算好的值,会对程序起到一定的优化作用,这也是一种数位DP优化方法,还是值得思考的

下面是代码:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
typedef long long ll;
ll f[103][1<<11][10];//f[i][j][k]表示遍历到第i位,出现次数状态为j在k进制下的方案数
int a[103];
int b;
ll dp(int pos,int s,int lead,int limit)
{
	if(!pos)	return (s==0);
	if(!lead&&!limit&&f[pos][s][b]!=-1) return f[pos][s][b];
	ll ans=0;
	int up=limit?a[pos]:(b-1);
	for(int i=0;i<=up;i++)
	{
		if(lead&&i==0)
			ans+=dp(pos-1,s,lead,limit&&(i==up));
		else
			ans+=dp(pos-1,s^(1<<i),lead&&(i==0),limit&&(i==up));
	}
	if(!lead&&!limit) f[pos][s][b]=ans;
	return ans;
}
ll solve(ll x)
{
	int pos=0;
	while(x)
	{
		a[++pos]=x%b;
		x/=b;
	}
	return dp(pos,0,1,1);
}
int main()
{
	ll l,r;
	int T;
	cin>>T;
	memset(f,-1,sizeof f);
	while(T--)
	{
		scanf("%d%lld%lld",&b,&l,&r);
		printf("%lld\n",solve(r)-solve(l-1));
	}
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值