Educational Codeforces Round 53 E. Segment Sum(数位DP)

Educational Codeforces Round 53 E. Segment Sum

题意:

问[L,R]区间内有多少个数满足:其由不超过k种数字构成。

思路:

数位DP裸题,也比较好想。由于没考虑到前导0,卡了很久。但最惨的是,由于每次求和的时候需要用到10的pos次幂,我是用提前算好的10的最高次幂,然后每次除以10往下传参。但我手贱取模了,导致每次除以10之后答案就不同余了,这个NC细节错误卡了我一小时才发现。

代码:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<map>
#include<queue>
#include<string>
#include<vector>
#include<cmath>
#include<climits>
#include<functional>
#include<set>
#define dd(x) cout<<#x<<" = "<<x<<" "
#define de(x) cout<<#x<<" = "<<x<<endl
#define fi first
#define se second
#define mp make_pair
#define pb push_back
using namespace std;
typedef long long ll;
typedef pair<ll,ll> P;
typedef vector<int> V;
typedef map<int,int> M;
typedef queue<int> Q;
typedef priority_queue<int> BQ;
typedef priority_queue<int,vector<int>,greater<int> > SQ;
const int maxn=2e5+10,INF=0x3f3f3f3f,mod=998244353;
int k,dig[30];
P dp[30][2000];
inline ll add(ll a,ll b)
{
  a+=b;
  return a>=mod?a-mod:a;
}
inline ll mul(ll a,ll b)
{
  return a*b%mod;
}
bool check(int sta)
{
  int cnt=0;
  for (int i=0;i<=9;++i)
    if (sta&(1<<i))
      cnt++;
  return cnt<=k;
}
P dfs(int pos,int sta,ll v,int lead,int lit)
{
  if (pos==-1)
    return mp(0,1);
  if (!lit&&dp[pos][sta].fi!=-1)
    return dp[pos][sta];
  int up=lit?dig[pos]:9;
  ll sum=0,cnt=0;
  for (int i=0;i<=up;++i)
  {
    int ns=(lead&&i==0)?sta:(sta|(1<<i));
    if (!check(ns))
      continue;
    P tmp=dfs(pos-1,ns,v/10,lead&&i==0,lit&&i==dig[pos]);
    cnt=add(cnt,tmp.se);
    sum=add(sum,add(tmp.fi,mul(tmp.se,mul(i,v))));
  }
  if (!lit)
    dp[pos][sta]=mp(sum,cnt);
  return mp(sum,cnt);
}
ll count(ll n)
{
  int pos=0;
  while (n)
  {
    dig[pos++]=n%10;
    n/=10;
  }
  ll v=1;
  for (int i=0;i<pos-1;++i)
    v*=10;
  return dfs(pos-1,0,v,1,1).fi;
}
int main()
{
  memset(dp,-1,sizeof(dp));
  ll l,r;
  cin>>l>>r>>k;
  cout<<add(count(r)-count(l-1),mod);
  return 0;
}

猜你喜欢

转载自www.cnblogs.com/orangee/p/9861418.html