CodeForces - 1073E :Segment Sum (數位DP)
You are given two integers
For example, if
InputThe only line of the input contains three integers
You are given two integers
For example, if
InputThe only line of the input contains three integers
Print one integer — the sum of numbers from
10 50 2Output
1230Input
1 2345 10Output
2750685Input
101 154 2Output
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; }