题解:P13650 [NOISG 2016] UnluckyFloors
P13650 [NOISG 2016] UnluckyFloors
题目传送门。\ 提交记录。
题目思路
个人感觉不是很难,是一道数位 DP 加二分的题目。
首先解决第一种情况,就是用
接着就是第二种情况,二分出常规数字刚好为
数位 DP 过程:
一,判断判断边界条件。当填数完毕时,返回
AC CODE:
#include<bits/stdc++.h>
using namespace std;
int a[17];
long long dp[17][10];
long long dfs(int address,bool limit,int pre){
if(address==-1)return 1;
if(!limit&&dp[address][pre]!=-1)return dp[address][pre];//记忆化搜索
int up=(limit==1)?a[address]:9;//上限
long long ans=0;
for(int i=0;i<=up;i++){
if(i==4)continue;
if(pre==1&&i==3)continue;
ans+=dfs(address-1,limit&&(i==up),i);//下一位数字
}
if(!limit)return dp[address][pre]=ans;//记忆化
else return ans;
}
long long sol(long long x){
int cnt=0;
while(x>0){
a[cnt++]=x%10;
x/=10;
}
return dfs(cnt-1,true,0)-1;
}
bool is(long long x){
string xx=to_string(x);
if(xx.find("4")!=-1||xx.find("13")!=-1)return false;
return true;
}
long long two(long long x){
long long l=1,r=5e18;
while(l<r){
long long mid=(l+r)/2;
if(sol(mid)<x)l=mid+1;
else r=mid;
}
return r;
}
int main(){
int t;
cin>>t;
memset(dp,-1,sizeof(dp));
while(t--){
long long op,X;
cin>>op>>X;
if(op==1){
if(!is(X))cout<<"-1\n";
else cout<<sol(X)<<"\n";
}else{
cout<<two(X)<<"\n";
}
}
return 0;
}