http://codeforces.com/contest/1271/problem/E
#include<iostream>
#include<algorithm>
using namespace std;
const long long N = 1e18+10;
long long n, k;
//检查这个数出现过多少次
long long check(long long ans)
{
long long poz = 1;
if ( ans & 1 ) poz = 0;//如果是奇数的话,以它开头的数只能是某数除以2之后转移过来
//如果是偶数的话,以它开头的数可以是奇数减一,也可以是除以2之后转移过来
long long cnt = 0;
//变成二进制看
while(ans<=n)
{
cnt+=min(n-ans + 1, 1ll<<poz);//在不超过ans~n里所有数的情况下
//每次加2的poz次方个“以目前的ans开头,且队列里check的这个数在第poz位(或poz-1位)”的数量
poz++;
ans*=2;
//以ans的出现次数是以ans*2开头的出现次数的2倍,其中一倍是除以2之后转移的,另一倍是减1之后转移的
}
return cnt;
}
int main()
{
cin>>n>>k;
long long ans = 0;
//用二进制来试出最终答案
//之前i选小了,大样例过不去,2的60次方才能到10的18次方
for (long long i=59;i>=0;i--)
{
ans |= (1ll<<i); //ans的第i位变为1 其他不变
if ( check(ans)<k ) ans ^=(1ll<<i);//如果小于k,把那一位变回来
}
cout<<ans<<endl;
return 0;
}
数学规律总结不出来可以打出一张表,一直盯着看……
#include<iostream>
#include<algorithm>
using namespace std;
const long long N=1e18+10;
int n;
int main(){
scanf("%d",&n);
for(int i=2;i<=n;i++){
cout<<"Path "<<i<<": ";
int q=i;
while(q!=1){
if(q%2) {
q--;
cout<<q<<" ";
}else{
q/=2;
cout<<q<<" ";
}
}
puts("");
}
return 0;
}