题意:
求第n个含有666的数。
题解:
第一反应就是数位dp然后二分答案,手残代码没写好wa好多次。正解是自动机dp,感觉大才小用了。我用记忆化写的,二分答案,但是有时候无法得到精确解,因此对结果进行稍微的波动处理下。
#include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<queue> #include<map> #include<set> using namespace std; #define B(x) (1<<(x)) typedef long long ll; void cmax(int& a,int b){ if(b>a)a=b; } void cmin(int& a,int b){ if(b<a)a=b; } const int oo=0x3f3f3f3f; const int MOD=1000000007; const int maxn=5100; const int maxm=21000; ll dp[20][11][11][2]; int bit[20]; ll dfs(int pos,int p1,int p2,int is,int f){ if(pos<1) return is; if(!f&&dp[pos][p1][p2][is]!=-1) return dp[pos][p1][p2][is]; int last= f ? bit[pos] : 9; ll res=0; for(int i=0;i<=last;i++){ res+=dfs(pos-1,p2,i,is||(p1==6&&p2==6&&i==6),f&&i==last); } if(!f) dp[pos][p1][p2][is]=res; return res; } ll Cnt(ll x){ int len=0; while(x){ bit[++len]=x%10; x/=10; } return dfs(len,0,0,0,1); } ll solve(int n){ if(n>72915400)return (ll)10000000000; ll l=0,r=(ll)10000000000,mid,ans,t; while(l<r){ mid=(l+r)>>1; t=Cnt(mid); if(t<n) l=mid+1; else r=mid-1,ans=mid; } t=Cnt(ans); if(t>=n){ while(Cnt(ans)>=n)ans--; ans++; }else{ while(Cnt(ans)<=n)ans++; ans--; } return ans; } int main(){ //freopen("G:\\read.txt","r",stdin); //freopen("G:\\a.txt","w",stdout); int n,T; memset(dp,-1,sizeof dp); scanf("%d",&T); while(T--){ scanf("%d",&n); printf("%I64d\n",solve(n)); } return 0; } /* 72915400 */