[SCOI2009] windy 數 (數位dp)
阿新 • • 發佈:2020-10-12
題目
演算法
應該是一道很經典的數位dp題
我們設dp[i][j]是填到第i位此時第i位的數是j的方案數
然後進行轉移(程式碼註釋)
程式碼
#include<iostream> #include<cstdio> #include<cmath> #define ll long long using namespace std; ll p,q,dp[15][15]; ll init(){//進行初始化 for(ll i = 0;i <= 9;i++) dp[1][i] = 1;//[0,9]顯然都是windy數 for(ll i = 2;i <= 10;i++) for(ll j = 0;j <= 9;j++) for(ll k = 0;k <= 9;k++) if(abs(j - k) >= 2) dp[i][j] += dp[i - 1][k];//先預處理好dp值 } ll work(ll x){//統計答案 ll a[15],len = 0,ans = 0; while(x){//將x分解 a[++len] = x % 10; x /= 10; } for(ll i = 1;i <= len - 1;i++)//先統計位數不足x位數的數 那這些數明顯都可以計算到方案中 for(ll j = 1;j <= 9;j++) ans += dp[i][j]; for(ll i = 1;i < a[len];i++)//位數和x位數相同 但最高位比x最高位小 顯然也可以 ans += dp[len][i]; for(ll i = len - 1;i >= 1;i--){//這裡處理位數和x位數相同 最高位 = x最高位的情況 for(ll j = 0;j <= a[i] - 1;j++) if(abs(j - a[i + 1])>= 2) ans += dp[i][j]; if(abs(a[i + 1] - a[i]) < 2) break; } return ans; } ll a,b; int main(){ scanf("%lld%lld",&a,&b); init(); cout<<work(b + 1) - work(a);//這裡應用字首和的思想 work計算[0,x)的方案數 那麼用work(b + 1) - work(a) 就是[a,b]的方案數 }