E. Segment Sum(数位dp)

题意:求一个区间内满足所有数位不同数字个数小于K的数字总和。比如:k=2   1,2,3所有数位的不同数字的个数为1满足,但是123数位上有三个不同的数字,即123不满足。

我们可以使用一个二进制的数字来记录某个数字是否已经出现,0为还没有出现,1表示该数字已经出现了。这里还需要注意前导零的干扰。

#include<iostream>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<stack>
#include<cstdio>
#include<map>
#include<set>
#include<string>
#include<queue>
using namespace std;
#define inf 0x3f3f3f3f
#define ri register int
typedef long long ll;

inline ll gcd(ll i,ll j){
	return j==0?i:gcd(j,i%j);
}
inline ll lcm(ll i,ll j){
	return i/gcd(i,j)*j;
}
inline void output(int x){
	if(x==0){putchar(48);return;}
	int len=0,dg[20];
	while(x>0){dg[++len]=x%10;x/=10;}
	for(int i=len;i>=1;i--)putchar(dg[i]+48);
}
inline void read(int &x){
    char ch=x=0;
    int f=1;
    while(!isdigit(ch)){
    	ch=getchar();
		if(ch==‘-‘){
			f=-1;
		}
	}
    while(isdigit(ch))
        x=x*10+ch-‘0‘,ch=getchar();
        x=x*f;
}
struct st{
	ll num;
	ll sum;
	st():num(0),sum(0){
	}
	st(ll num,ll sum):num(num),sum(sum){
	}
}dp[20][2000];
int maxs;
int a[20];
const ll mod=998244353;
int change(int n){
	int cnt=0;
	while(n){
		if(n&1)cnt++;
		n/=2;
	}
	return cnt;
}
st dfs(int pos,int sta,int pre,bool limit){
	if(pos==-1){
	//	cout<<pre<<endl;

		if(change(sta)<=maxs)
		return st(1,0);
		return st(0,0);
	}
	if(dp[pos][sta].num!=0&&!limit){
	//	printf("%d %lld\n",pos,dp[pos][sta].sum);
		return dp[pos][sta];
	}
	int up=limit?a[pos]:9;
	st ans;	

	for(int i=0;i<=up;i++){
		st tem;
		if(change(sta|(int)pow(2,i))>maxs)
		continue;
		if(pre==0&&i==0){
			 tem=dfs(pos-1,sta,0,i==up&&limit);
		}
		else{
			tem=dfs(pos-1,((int)pow(2,i))|sta,i,i==up&&limit);
		}
		ans.num+=tem.num;
		ans.num=ans.num%mod;
	ans.sum=(ans.sum+(ll)pow(10,pos)%mod*i*tem.num%mod+tem.sum)%mod;
	}
	if(!limit){
		dp[pos][sta]=ans;
	}
	return ans;
}
ll solve(ll n){
	int len=0;
	while(n){
		a[len++]=n%10;
		n/=10;
	}
	return dfs(len-1,0,0,true).sum;
}
int main(){
	ll l,r;
	scanf("%lld%lld%d",&l,&r,&maxs);
	printf("%lld",(solve(r)-solve(l-1)+mod)%mod);
	return 0;
}

  

原文地址:https://www.cnblogs.com/Zhi-71/p/10610306.html

时间: 2024-11-13 09:38:55

E. Segment Sum(数位dp)的相关文章

CodeForces - 1073E :Segment Sum (数位DP)

You are given two integers l l and r r (l≤r l≤r ). Your task is to calculate the sum of numbers from l l to r r (including l l and r r ) such that each number contains at most k k different digits, and print this sum modulo 998244353 998244353 . For

Codeforces1073E Segment Sum 【数位DP】

题目分析: 裸的数位DP,注意细节. 1 #include<bits/stdc++.h> 2 using namespace std; 3 4 const int mod = 998244353; 5 int k; 6 7 int dp[25][1024],sz[25][1024],cnt[25][1024]; 8 int pw10[25],hp[25],num; 9 10 int dfs(int now,int lst){ 11 if(now == 0) return 0; 12 int a

zoj 3962 Seven Segment Display(数位dp)

Seven Segment Display Time Limit: 2 Seconds      Memory Limit: 65536 KB A seven segment display, or seven segment indicator, is a form of electronic display device for displaying decimal numerals that is an alternative to the more complex dot matrix

ACdreamOJ 1154 Lowbit Sum (数位dp)

ACdreamOJ 1154 Lowbit Sum (数位dp) ACM 题目地址:ACdreamOJ 1154 题意: long long ans = 0; for(int i = 1; i <= n; i ++) ans += lowbit(i) lowbit(i)的意思是将i转化成二进制数之后,只保留最低位的1及其后面的0,截断前面的内容,然后再转成10进制数.即lowbit(i) = i&(-i). 每输入一个n,求ans 分析: 用二进制去考虑,可以发现这是个数位dp,如果当前第i

CF1073E Segment Sum 解题报告

CF1073E Segment Sum 题意翻译 给定\(K,L,R\),求\(L~R\)之间最多不包含超过\(K\)个数码的数的和. \(K\le 10,L,R\le 10^{18}\) 数位dp \(dp_{i,s}\)前\(i\)位出现集合\(s\)的贡献和和出现次数 然后记忆化的时候转移一下就行了 然而写的时候还是怪麻烦的 Code: #include <cstdio> #include <cstring> #define ll long long const int mo

51Nod 1009 数字1的个数 | 数位DP

题意: 小于等于n的所有数中1的出现次数 分析: 数位DP 预处理dp[i][j]存 从1~以j开头的i位数中有几个1,那么转移方程为: if(j == 1) dp[i][j] = dp[i-1][9]*2+pow(10,i-1);else dp[i][j] = dp[i-1][9]+dp[i][j-1]; 然后注意下对于每个询问统计的时候如果当前位为1需要额外加上他后面所有位数的个数,就是n%pow(10,i-1); 这样总复杂度log(n)*10 #include <bits/stdc++.

数位dp

1.[hdu3709]Balanced Number 1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<string> 5 #include<cstdlib> 6 #include<algorithm> 7 #include<ctime> 8 #include<cmath> 9 #include<queue>

LightOJ1068 Investigation(数位DP)

这题要求区间有多少个模K且各位数之和模K都等于0的数字. 注意到[1,231]这些数最大的各位数之和不会超过90左右,而如果K大于90那么模K的结果肯定不是0,因此K大于90就没有解. 考虑到数据规模,数据组数,这题状态这么表示: dp[i][j][k]:位数为i模K结果为j且各位数之和模K结果为k的数字个数 然后就是转移方程,最后就是统计.. 统计部分好棘手...半乱搞下AC的..还是对数位DP的这一部分太不熟悉了. 1 #include<cstdio> 2 #include<cstr

HDU 4734 F(x)(数位DP)

Description For a decimal number x with n digits (A nA n-1A n-2 ... A 2A 1), we define its weight as F(x) = A n * 2 n-1 + A n-1 * 2 n-2 + ... + A 2 * 2 + A1 * 1. Now you are given two numbers A and B, please calculate how many numbers are there betwe