您的位置:首页 > 其它

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

2018-11-14 03:23 363 查看

E. Segment Sum

题意

题意很简单,求l到r之间的所有数中不同数位数不超过k的数之和题意很简单,求l到r之间的所有数中不同数位数不超过k的数之和题意很简单,求l到r之间的所有数中不同数位数不超过k的数之和
1&lt;=l&lt;=r&lt;=1018  1&lt;=k&lt;=101&lt;=l&lt;=r&lt;=10^{18} \ \ 1&lt;=k&lt;=101<=l<=r<=1018  1<=k<=10

做法

一眼就知道是数位dp一眼就知道是数位dp一眼就知道是数位dp
而且我们也很容易想到状态的定义而且我们也很容易想到状态的定义而且我们也很容易想到状态的定义
数位dp时要往下传递都有哪些数位出现过,这个状态是(1&lt;&lt;10)的数位dp时要往下传递都有哪些数位出现过,这个状态是(1&lt;&lt;10)的数位dp时要往下传递都有哪些数位出现过,这个状态是(1<<10)的
由于我们要统计和,每个状态要保存两个值由于我们要统计和,每个状态要保存两个值由于我们要统计和,每个状态要保存两个值
满足状态的数字个数和当前状态数字对答案的贡献满足状态的数字个数和当前状态数字对答案的贡献满足状态的数字个数和当前状态数字对答案的贡献

坑点

由于本题中前导0对状态有影响,注意数位dp时前导0的问题由于本题中前导0对状态有影响,注意数位dp时前导0的问题由于本题中前导0对状态有影响,注意数位dp时前导0的问题

代码

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
const ll Mod = 998244353ll;

typedef pair<ll,ll> pll;
#define Se second
#define Fi first
ll l,r,k;
ll pow_[20];
int cal(ll x)
{
int ans=0;
while(x)
{
if(x&1) ans++;
x/=2;
}
return ans;
}
pll dp[20][1<<12][2];
ll a[20];
pll dfs(ll len,ll state,bool limit,bool lead)
{
if(len==0) return pll(1,0);//遍历结束,无需算对答案的贡献,但是要像正常数位dp一样统计满足条件的个数
if(!limit&&dp[len][state][lead].Se) return dp[len][state][lead];//注意带前导0的数位dp套路
pll ans=pll(0,0);
int up=limit?a[len]:9;
for(int i=0;i<=up;i++)
{
ll temp=state|((lead||i)<<i);
//若当前有前导0而且当前数位为0,则状态不更新
if(cal(temp)>k) continue;
//不满足答案的状态要去掉
pll tmp=dfs(len-1,temp,limit&&i==a[len],lead||i);
ans.Fi=(ans.Fi+tmp.Fi)%Mod;
ans.Se=(ans.Se+tmp.Se+(1LL*i*pow_[len-1]%Mod*tmp.Fi)%Mod)%Mod;
//当前数位对答案的贡献为当前数位所代表的值为i*pow[len-1]
//当前数位为i的数字个数为tmp.Fi
//总贡献为:i*pow_[len-1]%Mod*tmp.Fi
}
return dp[len][state][lead]=ans;
}
ll solve(ll x)
{
for(int i=0;i<20;i++)
{
for(int j=0;j<(1<<12);j++)
{
for(int l=0;l<2;l++)
{
dp[i][j][l].Fi=0;
dp[i][j][l].Se=0;
}
}
}
memset(a,0,sizeof(a));
int len=0;
while(x)
{
a[++len]=x%10;
x/=10;
}
return dfs(len,0,true,0).Se%Mod;
}
int main()
{
pow_[0]=1;
for(int i=1;i<20;i++) pow_[i]=pow_[i-1]*10%Mod;//每一位的贡献预处理
scanf("%lld%lld%lld",&l,&r,&k);
printf("%lld\n",(solve(r)-solve(l-1)+Mod)%Mod);
return 0;
}
阅读更多
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐