Live2d Test Env

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

You are given two integers

For example, if

Input

The only line of the input contains three integers

Output

Print one integer — the sum of numbers from

Examples
Input
10 50 2
Output
1230
Input
1 2345 10
Output
2750685
Input
101 154 2
Output
2189

题意:求区间[L,R]的满足digit种类不超过K的数字之和。

思路:与常规我数位DP不一样的是,这里求是不是个数,而是这些书之和。所以我们要记录一个二元组(x,y)分别表示(子树之和,子树叶子个数)。

(数位DP其实就是一棵树,子树相同的时候可以直接调用答案)

那么当前节点为根的树的信息=(所有子树的和+当前位*叶子个数,所有叶子个数之和)。

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
#define pii pair<int,int>
#define mp make_pair
using namespace std;
const int Mod=998244353;
pii dp[20][1<<10],O=mp(0,0);
int v[20],num[1<<10],K,q[20],tot;
pii dfs(int pos,int st,int lim)
{
    if(!lim&&dp[pos][st]!=O) return dp[pos][st];
    if(pos==1) return mp(0,1);
    int up=9; pii res=O,tmp; if(lim) up=q[pos-1];
    rep(i,0,up){
        if(num[st|(1<<i)]<=K){
            tmp=dfs(pos-1,st|(1<<i),lim&&i==up);
            (res.second+=tmp.second)%=Mod; 
            (res.first+=tmp.first)%=Mod;
            (res.first+=(ll)v[pos-1]*i%Mod*tmp.second%Mod)%=Mod;
        }
    }
    return dp[pos][st]=res;
}
int cal(ll x)
{
    if(x==0) return 0;
    tot=0; int ans=0;
    while(x) q[++tot]=x%10,x/=10;
    memset(dp,0,sizeof(dp));
    rep(i,1,tot){
        ll up=9; if(i==tot) up=q[tot];
        rep(j,1,up){
            pii tmp=dfs(i,1<<j,(i==tot)&&(j==q[tot]));
            (ans+=(ll)v[i]*j%Mod*tmp.second%Mod)%=Mod;
            (ans+=tmp.first)%=Mod;
        }
    }
    return ans;
}
int main()
{
    rep(i,1,1<<10) num[i]=num[i>>1]+(i&1);
    v[1]=1; rep(i,2,18) v[i]=(ll)v[i-1]*10%Mod;
    ll L,R; scanf("%lld%lld%d",&L,&R,&K);
    printf("%d\n",((cal(R)-cal(L-1))%Mod+Mod)%Mod);
    return 0;
}

 

posted @ 2018-12-01 20:04  nimphy  阅读(417)  评论(0编辑  收藏  举报