手打AC的第2道數位DP:BZOJ1799: [Ahoi2009]self 同類分布
阿新 • • 發佈:2017-09-22
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 同類分布