题解 P1647 【锁】
本蒟蒻做这道题时,还只有一个题解,于是本蒟蒻也想分享一下自己的方法。
首先找一下规律:(以下01串均为二进制表示)
当
当
当
可以发现,每
举个栗子,当
还不信?再看看
当
同样是满足这个规律的,对吧,按照这个规律,可以算出
按照此规律,能算出任何排名的数的函数如下。
long long work(long long k){//求出排名第k的数的数值
if(k==1)return 0LL;//如果是第一项,返回0
if(k==2)return 1LL;//如果是第二项,返回1
int t=0;long long kl=1;
while(kl<k){
kl<<=1;
t++;
}
t--;kl>>=1;//算出小于k的最大2的次幂
if(k-kl==1)return kl+work(k-1);
else return kl+work(k-kl-1);//这两句对应上方规律中的两个递推公式
}
那么,算出排名第
这个时候要用到分治的思想了:
我们先看张图
假设我们要求前
求
来到最后一步,
像这样大事化小,小事化了,不就是分治吗?
求解函数;
long long solve(long long k){
if(k==1)return 0LL;//返回1
if(k==2)return 1LL;//返回0
int t=0;long long kl=1;
while(kl<k){
kl<<=1;
t++;
}
t--;kl>>=1;
if(k-kl==1)return kl+work(k-1);//如果是2次幂+1的形式,最大的就是自身
else return (long long)kl+max(solve(k-kl-1),work(kl));//特判一下中间特殊的一项
}
最后是
#include<bits/stdc++.h>
using namespace std;
int n;
long long k;
long long work(long long k){
if(k==1)return 0LL;
if(k==2)return 1LL;
int t=0;long long kl=1;
while(kl<k){
kl<<=1;
t++;
}
t--;kl>>=1;
if(k-kl==1)return kl+work(k-1);
else return kl+work(k-kl-1);
}
long long solve(long long k){
if(k==1)return 0LL;
if(k==2)return 1LL;
int t=0;long long kl=1;
while(kl<k){
kl<<=1;
t++;
}
t--;kl>>=1;
if(k-kl==1)return kl+work(k-1);
else return (long long)kl+max(solve(k-kl-1),work(kl));
}
void write(long long x, int t){
if(t-1) write(x>>1,t-1);
putchar(x&1?'1':'0');
}
signed main(){
scanf("%d%lld",&n,&k);
write(solve(k),n);
return 0;
}