找规律
我在打表后发现,这一题可以进行二分答案,来做。
虽然整体并不呈现单调性但是偶数和奇数却呈现单调性。
这就很方便了。
我们可以分别在偶数和奇数上进行二分答案,然后取大即可。
但是,有一个困难,那就是如何求解每次这个数出现的集合数
如何求解呢?
刚开始我是使用暴力的,因为我隐隐约约的感觉复杂度应该不算很高吧。。。
但是,我错了,这个复杂度是很高的,甚至可以达到O(n)级别。
而远非我们所想的O(logn)
那么我该怎么办呢?苦恼啊苦恼
看了题解。发现其实题解也是在找规律。这不过他是从公式中找规律。
他发现对于一个数x,假设是奇数。
那么根据函数,2x,2x+1 肯定出现他
4x,4x+1,4x+2,4x+3肯定出现他。
8x,8x+1,8x+2,8x+3,8x+4,8x+5,8x+6,8x+7肯定出现他
那么诸如此类。。。
我们发现了一个规律,就是2的倍数倍数的向上加。
但是,重要的时边界处理。
真是妙啊,好题,好思维。当时赛场能做出来也是真的思维灵活啊!!!!!!!!!!
脑在颤抖!!!!!!!!!!!
#include<iostream> #include<algorithm> using namespace std; typedef long long ll; ll n,k; ll check(ll mid){ if (mid>n)return 0; ll ans = 0;ll dig = 2; if (mid&1){ mid<<=1; ans++; } if (mid>n)return ans; while (mid+dig-1<=n){ ans+=dig; mid<<=1; dig<<=1; } if (n-mid+1>0)ans+=n-mid+1; return ans; } ll Solve(){ ll lft = 1,rgt = n/2; if (check(2)<k)return -1; ll ans = 0; while (lft<=rgt){ ll mid = (lft+rgt)>>1; if (check(mid<<1)>=k){ ans = max(ans,mid<<1); lft = mid+1; } else rgt = mid-1; }return ans; } ll Solve2(){ ll lft = 0;ll rgt; if (n&1)rgt=n/2; else rgt = n/2 - 1; ll ans = 0; while (lft<=rgt){; ll mid = (lft+rgt)>>1; if (check(mid<<1|1)>=k){ ans = max(ans,mid<<1|1); lft=mid+1; } else rgt = mid-1; }return ans; } int main(){ cin>>n>>k; cout<<max(Solve2(),Solve())<<endl; }