1. 程式人生 > >51nod 1623 完美消除(數位DP)

51nod 1623 完美消除(數位DP)

eof div ... 狀態 class esp bool turn gpo

  首先考慮一下給一個數如何求它需要多少次操作。

  顯然用一個單調棧就可以完成:塞入棧中,將比它大的所有數都彈出,如果棧中沒有當前數,答案+1。

  因為數的範圍只有0~9,所以我們可以用一個二進制數來模擬這個棧,並塞到DP的狀態裏。

  設$dp[i][j][k]$表示前i位數,已經進行了j次操作,棧的狀態為k的方案數。

  每次枚舉一個數的時候,先把比這個數大的數在狀態中都清零,再看看狀態中有沒有這個數,沒有的話答案+1。

  註意需要把狀態初始值設為0在棧中...T T

技術分享圖片
#include<iostream>
#include<cstring>
#include
<cstdlib> #include<cstdio> #define ll long long using namespace std; ll l, r, K; ll dp[20][20][1<<10]; int a[20]; ll dfs(int pos, int k, int st, bool limit) { if(!pos) return k==K; if(!limit && dp[pos][k][st]!=-1) return dp[pos][k][st]; int up=limit?a[pos]:9
; ll ans=0; for(int i=0;i<=up;i++) { int now=st; for(int j=i+1;j<=9;j++) now^=((now & (1<<j))!=0)<<j; if(st&(1<<i)) ans+=dfs(pos-1, k, now, limit && i==up); else if(k<K) ans+=dfs(pos-1, k+1, now|(1<<i), limit && i==up); }
if(!limit) dp[pos][k][st]=ans; return ans; } ll solve(ll x) { int pos=0; while(x) a[++pos]=x%10, x/=10; return dfs(pos, 0, 1, 1); } int main() { memset(dp, -1, sizeof(dp)); scanf("%lld%lld%lld", &l, &r, &K); printf("%lld\n", solve(r)-solve(l-1)); }
View Code

51nod 1623 完美消除(數位DP)