1 条题解

  • 0
    @ 2025-8-24 22:46:57

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar falling_cloud
    便舍此间繁华尽 留待梦中重游时

    搬运于2025-08-24 22:46:57,当前版本为作者最后更新于2023-07-25 19:16:24,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    首先发现题目要求使其最大的式子的每一个二进制位计算是独立的,单独拆出二进制位的第 ii 位,设 xx 为该位为 11 的数字个数。由于仅当选取的两个数中的一个数第 ii 位为 00,另一个数第 ii 位为 11 时,产生 2i2^i 的贡献,所以对于第 ii 位,总的贡献为 x×(nx)×2ix\times (n-x)\times 2^i

    这时考虑对于某一位进行翻转带来的贡献,设原本有 xkx_k 个数第 kk 位为 00yk(=nxk)y_k(=n-x_k) 个数第 kk 位为 11,贡献为 xkykx_ky_k,在对第 kk 位进行一次 00 翻转为 11 的操作后,贡献变为 (xk+1)(yk1)=xkyk+ykxk1(x_k+1)(y_k-1)=x_ky_k+y_k-x_k-1,贡献差为 ykxk1y_k-x_k-1。可以发现,这个贡献是具有单调性的。所以可以直接用优先队列维护。

    实现方面细节不算很多,时间复杂度为 O(PlogK)O(P \log K)

    #include <bits/stdc++.h>
    #define ll long long
    #define endl '\n'
    using namespace std;
    const int N = 1e5 + 5;
    int a[N],sum1[50]={0},sum2[50]={0};
    queue <int> q1[50],q2[50];
    struct pi
    {
    	int x;	ll w;
    	bool operator > (const pi &xx) const{return w>xx.w;}
    	bool operator < (const pi &xx) const{return w<xx.w;}
    };
    priority_queue <pi,vector<pi>,less<pi> > q;
    signed main()
    {
    	ios::sync_with_stdio(false);
    	cin.tie(0);	cout.tie(0);
    	int n,k,p,i,j,x,y,z;
    	cin>>n>>k>>p;
    	k--;
    	for(i=1;i<=n;i++)	cin>>a[i];
    	for(i=k;i>=0;i--)
    		for(j=1;j<=n;j++)
    			if((a[j]>>i)&1)	sum1[i]++,q1[i].push(j);
    			else			sum2[i]++,q2[i].push(j);
    	for(i=0;i<=k;i++)
    	{
    		if(sum1[i]>=sum2[i])	
    			q.push((pi){i,1ll*(sum1[i]-sum2[i]-1)*(1<<i)});
    		else
    			q.push((pi){i,1ll*(sum2[i]-sum1[i]-1)*(1<<i)});
    	}
    	for(i=1;i<=p;i++)
    	{
    		x=q.top().x;
    		y=q.top().w;
    		q.pop();
    		if(sum1[x]>=sum2[x])
    		{
    			cout<<q1[x].front()<<" "<<x<<endl;
    			q2[x].push(q1[x].front());
    			q1[x].pop();
    			sum1[x]--,sum2[x]++;
    			if(sum1[x]>=sum2[x])	
    				q.push((pi){x,1ll*(sum1[x]-sum2[x]-1)*(1<<x)});
    			else
    				q.push((pi){x,1ll*(sum2[x]-sum1[x]-1)*(1<<x)});
    		}
    		else
    		{
    			cout<<q2[x].front()<<" "<<x<<endl;
    			q1[x].push(q2[x].front());
    			q2[x].pop();
    			sum1[x]++,sum2[x]--;
    			if(sum1[x]>=sum2[x])	
    				q.push((pi){x,(1ll*sum1[x]-sum2[x]-1)*(1<<x)});
    			else
    				q.push((pi){x,(1ll*sum2[x]-sum1[x]-1)*(1<<x)});
    		}
    	}
    	return 0;
    }
    
    • 1

    信息

    ID
    8651
    时间
    2000ms
    内存
    512MiB
    难度
    4
    标签
    递交数
    0
    已通过
    0
    上传者