本文主要是介绍牛客挑战赛45友人(思维+二分+位运算),希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
思路:出了位运算其实需要按位进行考虑,不过一拿到这个题的时候变量较多,不好下手。
但是如果能定下一个量,就可以方便了。考虑二分z的上界,假如知道了z的上界,那么后面的式子就可以通过位运算的角度去枚举出最优解。
那么怎么去知道z的上界,由于是等差数列,所以整个式子可以变成一个单调递增的(sort)。而且贪心去考虑,优先把数字大的变成min(Ai,z)更优。于是sort从小到大序列,然后从后面开始,o(n)枚举长度,在一个长度内确定下来能否满足有z使得前面不变的和+后面变小的和<=y。从而获得z的上界。
已经有了z的范围[1,max],如果k第i位为1,那么我们z这一位尽量去放1,在不超过上界的情况下,如此能让该位异或变0,从而z^k+k-z变小。如果k第i位是0,如果放1和0有什么区别嘛。放1的话后面的z变大2^i,整体式子减小2^i,但是注意该位和k的异或会导致增大2^i.所以做无用功,还浪费到上界的有效大小。所以给予0即可。
最后累加枚举最小。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+100;
typedef long long LL;
LL a[maxn];
LL n,A1,d,k,y;
int main(void)
{cin.tie(0);std::ios::sync_with_stdio(false);cin>>n>>A1>>d>>k>>y;LL total=0;for(LL i=1;i<=n;i++){a[i]=A1+(i-1)*d; total+=a[i];}sort(a+1,a+1+n);LL ss=0;LL ans=1e18;for(LL i=n;i>=1;i--){ss+=a[i];LL l=-1;LL r=a[i]-1;while(l<r){LL mid=(l+r+1)>>1;if(total-ss+mid*(n-i+1)<=y) l=mid;else r=mid-1; }if(l==-1) continue;///在此区间内就算k取0都没法满足,不合法区间 LL high=l;LL res=0;for(LL j=60;j>=0;j--){if((k>>j)&1){if(res+(1<<j)<=high){res+=(1<<j);}} }ans=min(ans,(n-i+1)*( (res^k)+k-res) );}cout<<ans<<endl;
return 0;
}
这篇关于牛客挑战赛45友人(思维+二分+位运算)的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!