洛谷2657 windy數(數位DP)
阿新 • • 發佈:2018-11-11
傳送門
【題目分析】
數位DP經典題了。
考慮直接統計R內的windy數和L-1內的windy數,兩者相減即為L~R之間的windy數。
考慮DP,記錄當前位以及上一位所填的數,當前是否前面為前導零,以及前面一段是否與原數相同。
然後按題意逐位計算即可。
然後就會驚訝的發現TLE了。。。。。。
所以考慮優化:如果當前沒有受任何限制,那麼可以直接記錄下當前位置的值,記憶化搜尋。
【程式碼~】
#include<bits/stdc++.h> using namespace std; typedef long long LL; const int MAXN=15; LL l,r; int num[MAXN],cnt; int dp[MAXN][MAXN]; LL Read(){ LL i=0,f=1; char c; for(c=getchar();(c>'9'||c<'0')&&c!='-';c=getchar()); if(c=='-') f=-1,c=getchar(); for(;c>='0'&&c<='9';c=getchar()) i=(i<<3)+(i<<1)+c-'0'; return i*f; } int DP(int pos,int last,int iszero,int limit){ if(pos==0) return !iszero; if(!iszero&&!limit&&dp[pos][last]!=-1) return dp[pos][last]; int sx=limit?num[pos]:9,ret=0; for(int i=0;i<=sx;++i){ int delta=abs(i-last); if(!iszero){ if(delta>=2){ ret+=DP(pos-1,i,iszero,limit&&i==num[pos]); } } else{ ret+=DP(pos-1,i,i==0,limit&&i==num[pos]); } } if(!iszero&&!limit) return dp[pos][last]=ret; return ret; } int solve(int x){ cnt=0; while(x){ num[++cnt]=x%10; x/=10; } return DP(cnt,0,1,1); } int main(){ memset(dp,-1,sizeof(dp)); l=Read(),r=Read(); cout<<solve(r)-solve(l-1); return 0; }