CodeForces - 1073E :Segment Sum (数位DP)
You are given two integers
For example, if
InputThe only line of the input contains three integers
OutputPrint one integer — the sum of numbers from
ExamplesInput
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; }
It is your time to fight!