1 条题解

  • 0
    @ 2026-9-24 10:22:26

    考虑为什么先手必胜。

    注意到后手永远无法改变石子的总个数,而只有石子个数为 00 时会出现一方输的情况。

    那么也就是后手需要尽可能保证石子多,先手尽可能让石子少。

    可以观察出这样一个过程,每一步先手选一个位置清空,后手把一个位置重新平分,这样对于每个堆所需要的次数是固定的。

    那这题做完了吗?

    注意到初始是先手先操作,而做完上述操作一轮后会变成后手先操作,而后手在已经平均的情况下操作是不优的。

    而后手只有在操作 2k2^k 时会使得上述过程的次数 −1-1,而且如果继续操作只会保持不变,所以现在先手需要最大化能让后手强制 −1-1 的数量。

    先手可以先操作若干次来让对手处于 2k2^k 的状态,而注意到如果当前总石子数是奇数,分成两部分后,后手也可以来回移动,所以要在偶数的情况下让后手选。

    那么会发现 (2k−1)×2(2^k-1)\times 2 是一个很关键的状态,因为这样是先手不断选这个数的情况下最后一次偶数,而每次后手选到这个会使得 kk 减少 11。

    这样问题就很明显了,用堆维护所有 kk,先手每次会删去一个 kk,后手每次可以给一个 kk 减去 11,最后双方分别最小化/最大化 删去的 kk 中 00 的数量(不能减到小于 00)。

    用堆维护,双方每次一定都选最大的那个数,时间复杂度 O(nlog⁡n)\mathcal{O}(n\log n),可以优化至线性。

    
    i64 n,a[maxn];
    i64 calc1(i64 x){
    	if(!x)return 0;
    	return calc1(x/2)+1;
    }
    int main(){
    	// freopen("1.in","r",stdin);
    	// freopen("1.out","w",stdout);
    	
    	n=read();
    	i64 s1=0,mn=1e9,Ans=0;
    	priority_queue<i64>qwq;
    	F(i,1,n){
    		a[i]=read();i64 k=__lg(a[i]);
    		while(__builtin_popcount(a[i]+1)!=1)
    			a[i]/=2,s1++;
    		a[i]=__builtin_popcount(a[i]);
    		s1+=a[i]+1;
    		qwq.push(a[i]);
    		if(!a[i])s1--;
    		// printf("%lld\n",a[i]);
    	}
    	bool xo=0;
    	while(qwq.size()){
    		i64 u=qwq.top();qwq.pop();
    		// cout<<u<<endl;
    		if(xo==0);
    		else{
    			if(u==1)s1--,xo=0;
    			else qwq.push(u-1);
    		}
    		xo^=1;
    	}
    	printf("%lld\n",2*s1-1);
    	return 0;
    }
    
    • 1

    信息

    ID
    5763
    时间
    2000ms
    内存
    228MiB
    难度
    (无)
    标签
    递交数
    0
    已通过
    0
    上传者