NKOJ P4258 土撥鼠獵人【數位DP】
阿新 • • 發佈:2018-12-11
題解來源於rgnoH:
#include <cmath> #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define ll long long #define rep(i,x,y) for(ll i=(x);i<=(y);i++) #define repl(i,x,y) for(ll i=(x);i<(y);i++) #define repd(i,x,y) for(ll i=(x);i>=(y);i--) using namespace std; const ll N=25; const ll M=15; const ll Inf=1e18; ll n,w[N],f[N][M][M][2][2][2][2]; inline ll read() { ll x=0;char ch=getchar();bool f=0; while(ch>'9'||ch<'0'){if(ch=='-')f=1;ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?-x:x; } void split(ll x) { w[0]=0; while(x) { w[++w[0]]=x%10;x/=10; } rep(i,1,w[0]/2) swap(w[i],w[w[0]+1-i]); } ll dp(ll len,ll sec,ll thi,ll lim,ll lim1,ll lim2,ll lim3) { if(~f[len][sec][thi][lim][lim1][lim2][lim3]) return f[len][sec][thi][lim][lim1][lim2][lim3]; if(len==w[0]+1) { if(lim1&&(!(lim2&lim3))) return true; return false; } ll ans=0,max_num=lim?w[len]:9; ll nlim,nlim1,nlim2,nlim3; rep(i,0,max_num) { if(!lim1) { if(lim&&i==w[len]) nlim=1; else nlim=0; if(i) nlim1=1; else nlim1=0; nlim2=nlim3=0; ans+=dp(len+1,i,sec,nlim,nlim1,nlim2,nlim3); } else { if(lim&&i==w[len]) nlim=1; else nlim=0; if(i) nlim1=1; else nlim1=lim1; if(i==sec) nlim2=1; else nlim2=lim2; if(i==sec-1) nlim3=1; else nlim3=lim3; if(!(i==3&&sec==3&&thi==2)&&(!(nlim2&nlim3))) ans+=dp(len+1,i,sec,nlim,nlim1,nlim2,nlim3); } } return f[len][sec][thi][lim][lim1][lim2][lim3]=ans; } bool check(ll x) { split(x); memset(f,-1,sizeof(f)); return dp(1,11,11,1,0,0,0)>=n; } int main() { n=read(); ll l=1,r=Inf; while(l<=r) { ll mid=l+r>>1; if(check(mid)) r=mid-1; else l=mid+1; } printf("%lld",l); return 0; }