codeforces1073E解题报告

E. Segment Sum
time limit per test
1 second
memory limit per test
256 megabytes
input
standard input
output
standard output

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

.

For example, if k=1
then you have to calculate all numbers from l to r such that each number is formed using only one digit. For l=10,r=50 the answer is 11+22+33+44=110

.
Input

The only line of the input contains three integers l
, r and k (1≤l≤r<1018,1≤k≤10

) — the borders of the segment and the maximum number of different digits.
Output

Print one integer — the sum of numbers from l
to r such that each number contains at most k different digits, modulo 998244353

.
Examples
Input
Copy

10 50 2

Output
Copy

1230

Input
Copy

1 2345 10

Output
Copy

2750685

Input
Copy

101 154 2

Output
Copy

2189

Note

For the first example the answer is just the sum of numbers from l
to r which equals to 50⋅512−9⋅102=1230. This example also explained in the problem statement but for k=1

.

For the second example the answer is just the sum of numbers from l
to r which equals to 2345⋅23462=2750685

.

For the third example the answer is 101+110+111+112+113+114+115+116+117+118+119+121+122+131+133+141+144+151=2189

.

题意:给出一个左边界 L 和右边界 R ,然后一个数k
问从L到R的数中不相同的数不超过k个的和是多少
比如2234 不相同的数是3个,1234567890不相同的数是10个,111不相同的数是1个
举个例子:1 9 1
从1到9中不相同的数不超过1个的和是1+2+。。。+9=45
大概就这样。。。
思路:这道题是用数位dp来做的。
首先k<=10,那么我们可以用二维dp来做,第一维表示位数,第二维表示不同的数出现的情况,dp[20][1<<10],当我们dfs到第pos位的时候,之前出现过的数字用二进制转换,比如前面出现过9和2 那么现在的状态state==1000000100(2)=516。这样子可以把所有情况都考虑一遍
而且这样我们也可以判断不相同的数是多少个。然后我们就可以找到哪些数是符合条件的。
之后我们要计算他们的和。这样:假如我们搜索到xx3xx,后面符合条件的数是4个,那么和一定有300*4,这个应该不用解释了。所以我们在搜索下一位的时候我们可以用这一位数 x 乘 (10^pos) 乘 之后找到符合的数量y 这就是这个pos位的和,到上一位后我们要加上这一位的和。差不多就是这样
坑点:注意精度和前导零
AC代码:

#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long int ll;
const ll MOD=998244353;
ll num[20];
ll n,m,k;
struct Sum
{
	ll a,b;		//a==和,b==数量 
}dp[20][1<<11];
void Init()
{
	memset(dp,-1,sizeof(dp));
	return ;
}
ll judge(ll x)		//找出不相同的数有多少个
{
	int ans=0;
	while (x>0)
		{
			ans+=x&1;
			x>>=1;
		}
	return ans;
}
ll pow(ll x)		//计算和
{
	ll ans=1;
	for (int i=1;i<=x;i++)
		ans=ans*10;
	return ans%MOD;
}
Sum dfs(int pos,bool now,int sta,bool limit)	//层,前导0	,数量限制,上限
{
	Sum sum,ans;
	sum.a=0;sum.b=0;
	ans.a=0;ans.b=0;
	if (pos==-1)
		{
	//		cout<<sta<<endl;
			sum.b=1;
			return sum;
		}
	if (!limit&&dp[pos][sta].b!=-1)
		return dp[pos][sta];
	int up=limit?num[pos]:9;
//	cout<<pos<<"----------------------"<<endl;
	for (int i=0;i<=up;i++)
		{
			int x=sta|((now||i)<<i);		//如果有前导0,就是now和i都是false和0,就不要算
			if (judge(x)>k) continue;
	//		cout<<pos<<" "<<i<<endl;
			sum=dfs(pos-1,now||i,x,limit&&i==up);
			ans.b=(ans.b+sum.b)%MOD;		//记录符合的个数 
			ans.a=(ans.a+sum.a+1ll*i*pow(pos)*sum.b%MOD)%MOD;		//算和 
		}
	if (limit)	return ans;
	dp[pos][sta].a=ans.a;
	dp[pos][sta].b=ans.b;
	return dp[pos][sta];
}
ll solve(ll x)
{
	int ans=0;
	memset(num,0,sizeof(num));
	while (x>0)
		{
			num[ans++]=x%10;
			x=x/10;
		}
	return dfs(ans-1,false,0,true).a;
} 
int main()
{
	scanf("%lld%lld%lld",&n,&m,&k);
	Init();
	printf("%lld\n",(solve(m)-solve(n-1)+MOD)%MOD);
	return 0;
}

再说一遍,注意精度

发布了46 篇原创文章 · 获赞 2 · 访问量 3205

猜你喜欢

转载自blog.csdn.net/z1164754004z/article/details/88878877