E. Segment Sum (数位dp)Educational Codeforces Round 53 (Rated for Div. 2)

本文介绍了一种使用数位动态规划(数位DP)的方法,解决在给定范围内寻找满足特定数位限制条件的数字总和问题。具体地,对于任意整数l和r以及整数k,我们需要计算在[l, r]区间内,所有数字中只包含k个不同数位的数字总和。文章详细展示了代码实现,通过递归的数位DP算法,有效地解决了这一问题。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://codeforces.com/contest/1073/problem/E

参考链接:https://blog.youkuaiyun.com/qq_38677814/article/details/83415782

题意:给出l,r,k,在范围 [ l , r ] 内找出数字(满足每个数字的数位只能有k个不同)的总和,例如:k=2,那么101满足只有两种不同的数字。

 

题解:数位dp,详情见代码,此代码是直接搬上面博主的,写得太好了。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;

typedef long long LL;
const LL MOD = 998244353LL;

int cnt[20];
LL ppow[22];
LL a,b,k;

struct Point{
	LL x,y;///x代表符合条件的有几个,y代表对答案的贡献
}dp[20][1<<12][2];


Point dfs(LL len,LL state,bool limit,bool non_zero){///这里要前导0
    
    
	if(len==0) return Point{1,0};///一个数字枚举完了 符合条件的++ 不再产生贡献(之前已经计算了)
	if(!limit&&dp[len][state][non_zero].y) return dp[len][state][non_zero];
	///记忆化
	Point ans = Point{0,0};///初始化ans
	int Max = limit?cnt[len]:9;///套路
	for(int i=0;i<=Max;++i){
		LL temp = state|((non_zero||i)<<i); ///改变状态
		if(__builtin_popcountLL(temp)>k) continue;///删掉错误的状态
		Point t = dfs(len-1,temp,limit&&i==Max,non_zero||i);///临时变量
		ans.x = (ans.x+t.x)%MOD;///符合条件的个数增加
		ans.y = (ans.y+t.y+1LL*i*ppow[len-1]%MOD*t.x%MOD)%MOD;///当前数位的贡献增加
	}
	return dp[len][state][non_zero]=ans;
}
LL solve(LL x){
	memset(dp,0,sizeof dp);
	memset(cnt,0,sizeof cnt);
	int len=0;
	while(x){
		cnt[++len]=x%10;
		x/=10;
	}
	return dfs(len,0,true,0).y;
	///最高位开始枚举 现在还没有任何数位上有数字 到达了最高位 有前导零zero=true non_zero = false
}
int main(){
	ppow[0]=1;
	for(int i=1;i<20;++i) ppow[i]=ppow[i-1]*10%MOD;
	
	while(~scanf("%lld%lld%lld",&a,&b,&k)){
	printf("%lld\n",(solve(b)-solve(a-1)+mod)%mod);
	}
	return 0;	
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值