1. 程式人生 > >手打AC的第2道數位DP:BZOJ1799: [Ahoi2009]self 同類分布

手打AC的第2道數位DP:BZOJ1799: [Ahoi2009]self 同類分布

pac div cstring () ace -s 難度 搜索 bsp

先講下個人對於數位DP的看法吧。。。

挺難理解的

首先需要明白的一點:前綴和很重要

其次:必須用到記憶化搜索(本人蒟蒻,必須要用這種方法降低難度)

然後呢,需要判斷約束的條件:(1.前綴0(有時需要,有時不需要);2.數位的取值(基本都需要))

比如這道題,乍一看無思路,然後呢。。。。

就會出現很神奇的事情

大膽嘗試(第一次)3維(題解本來是4維的。。。)

居然就XJB A了...

略顯蛋疼。。。

回歸正題*2;

本題的狀態有些難找,但是由於數位最多的也只有pos,所以就可枚舉所有的數位和。。。

記錄幾個狀態(sum(數位和,最後必須變回0),val(表示數的值),以及數位即可)

代碼如下


#include<iostream>
#include
<cstdio> #include<cstring> #include<algorithm> #include<cmath> #define ll long long using namespace std; ll dp[20][180][180],n,m,a[1005]; ll dfs(int pos,int sum,int val,int mod,int limit){ if (sum-9*(pos+1)>0) return 0; if (pos==0) return sum==0 && val==0; if (!limit && dp[pos][sum][val]!=-1
) return dp[pos][sum][val]; int up=limit?a[pos]:9; ll ans=0; for (int i=0; i<=up; i++) { if (sum-i<0) break; ans+=dfs(pos-1,sum-i,(val*10+i)%mod,mod,limit && a[pos]==i); } if (!limit) dp[pos][sum][val]=ans; return ans; } ll solve(ll x){ ll pos
=0; while (x){ a[++pos]=x%10; x/=10; } ll ans=0; for (int i=1; i<=pos*9; i++) { memset(dp,-1,sizeof(dp)); ans+=dfs(pos,i,0,i,1); } return ans; } int main(){ scanf("%lld%lld",&n,&m); printf("%lld",solve(m)-solve(n-1)); return 0; }

總結:

  打了一天的數位DP了,整個人也廢了。。。。

手打AC的第2道數位DP:BZOJ1799: [Ahoi2009]self 同類分布