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;
}
再说一遍,注意精度