1. 程式人生 > >The 2018 ACM-ICPC上海大都會賽 J Beautiful Numbers (數位DP)

The 2018 ACM-ICPC上海大都會賽 J Beautiful Numbers (數位DP)

mes div spa ems urn 余數 limit style 狀態

題意:求小於等於N且能被自己所有位上數之和整除的數的個數。

分析:裸的數位dp。用一個三位數組dp[i][j][k]記錄:第i位,之前數位之和為j,對某個mod余數為k的狀態下滿足條件的個數。這裏mod的值就是小於等於N的數中,所有可能出現的數位之和。所以solve函數中需要對dfs函數做一個循環,上限是9*pos(數位之和不會超過9*pos)。

還有需要註意的是,在遞歸的時候可以通過判斷當前數位之和sum是否超過mod,超過的話肯定在這個狀態下沒有滿足條件的數,以此剪枝優化。

#include<bits/stdc++.h>
using namespace std;
const int
maxn=3e5+5; const int INF =0x3f3f3f3f; typedef long long LL; int a[20]; LL dp[13][105][150]; //dp[i][j][k]記錄 第i位,前面數位之和為j,對某個mod的余數是k的狀態下滿足條件的個數 int mod; LL dfs(int pos,int sum,int remain,bool limit){ if(pos==-1) return (sum==mod && !remain); if(dp[pos][sum][remain]!=-1 && !limit) return
dp[pos][sum][remain]; int up = limit? a[pos]:9; LL res=0; for(int i=0;i<=up;++i){ if(i+sum>mod) break; //剪枝 res+=dfs(pos-1,sum+i,(remain*10+i)%mod,limit && i==a[pos]); } if(!limit) dp[pos][sum][remain] = res; return res; } LL solve(LL N) {
int pos=0; LL x=N; while(x){ a[pos++]=x%10; x/=10; } LL res=0; for(int i=1;i<=9*pos;++i){ mod=i; memset(dp,-1,sizeof(dp)); //這裏的dp數組記錄的只是針對一種模數的狀態,所以每次都要清空 res+=dfs(pos-1,0,0,true); } return res; } int main(){ int T,M,num,t,x; LL N; #ifndef ONLINE_JUDGE freopen("in.txt","r",stdin); freopen("out.txt","w",stdout); #endif while(scanf("%lld",&N)==1){ printf("%lld\n",solve(N)); } return 0; }

The 2018 ACM-ICPC上海大都會賽 J Beautiful Numbers (數位DP)