【数位dp】【二分】Gym

数位dp预处理之后,可以容易得到f(x),代表小于等于x的数中,有多少个不含13的。然后就能二分答案啦。

#include<cstdio>
#include<iostream>
using namespace std;
typedef unsigned long long ull;
ull n;
ull f[19][3];
void init()
{
    f[0][0]=1;
    for(int i=1;i<=18;++i)
      {
          f[i][0]=f[i-1][0]*10-f[i-1][1];
          f[i][1]=f[i-1][0];
          f[i][2]=f[i-1][2]*10+f[i-1][1];
      }
}
ull work(ull x)
{
    ull ans=0,t=x,bit[25],len=0;
    while(t)
      {
          bit[++len]=t%10;
          t/=10;
      }
    ull is=1;
    for(int i=len;i>1;--i){
    	if(bit[i]==1 && bit[i-1]==3){
    		is=0;
    		break;
    	}
    }
    bit[len+1]=bit[len+2]=0;
    bool flag=0;
    for(int i=len;i;--i)
      {
          if(bit[i+1]==3 && bit[i+2]==1)
            flag=1;
          ans+=f[i-1][2]*bit[i];
          if(flag)
            ans+=bit[i]*f[i-1][0];
          else
          {
              if(bit[i] > 1)
                  ans+=f[i-1][1];
              if(bit[i+1] == 1 && bit[i] > 3)
                  ans+=f[i][1];
          }
      }
    return x-ans+is-1;
}
int T;
int main()
{
    init();
    freopen("hotel.in","r",stdin);
    freopen("hotel.out","w",stdout);
    scanf("%d",&T);
//    work(14);
    for(;T;--T)
      {
          cin>>n;
          ull l=1,r=(ull)2000000000000000000ll;
          while(l<r){
          	ull mid=(l+r)/(ull)2;
          	if(work(mid)>=n){
          		r=mid;
          	}
          	else{
          		l=mid+1;
          	}
          }
          cout<<l<<endl;
      }
    return 0;
}
原文地址:https://www.cnblogs.com/autsky-jadek/p/7131842.html