牛客挑战赛45友人(思维+二分+位运算)

62 篇文章 2 订阅
13 篇文章 0 订阅


思路:出了位运算其实需要按位进行考虑,不过一拿到这个题的时候变量较多,不好下手。

但是如果能定下一个量,就可以方便了。考虑二分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;
}

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值