牛客多校2022 2
牛客多校2022 2
C Link with Nim Game
\(nim\)游戏,问必胜方想尽快结束,必败方想尽量拖,问回合数,第一步取石子的方案数。
必败方选择\(lowbit\)最小的一组石子堆取\(1\),必胜方只能选择另一个\(lowbit\)最小的一组石子取\(1\),所以当一个局面是必败时,剩余局数为剩下石子总数。
必胜方起手要尽量取最多的石子,方案数也很好算。
考虑必败方的方案数。一个\(lowbit\)为\(1000\)的石子堆取\(1\)后,异或和变化为\(1111\),有且仅当一个数的前\(4\)位为\(1XXX\)其中\(X\)至少存在一个为\(1\)时也可以使异或和变化为\(1\)且减少大于\(1\)的石子。所以必败方选择的石子堆必须满足第\(x\)位为第一个\(1\)时,不存在另外一个石子堆满足第\(x\)位为\(1\)且存在更低位的\(1\).
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
#define int long long
const int INF=1e18;
const int N=5e5+500;
int a[N],w[N];
signed main(){
int T;
scanf("%lld",&T);
while(T--){
int n;
scanf("%lld",&n);
int sum=0;
int tot=0;
for(int i=1;i<=n;i++)scanf("%lld",&a[i]),sum^=a[i],tot+=a[i];
if(sum){
int ans=INF;
int cnt=0;
for(int i=1;i<=n;i++){
sum^=a[i];
if(a[i]>sum){
if(tot-(a[i]-sum)+1==ans)cnt++;
else if(ans>tot-(a[i]-sum)+1)ans=tot-(a[i]-sum)+1,cnt=1;
}
sum^=a[i];
}
cout<<ans<<" "<<cnt<<endl;
}
else{
int ans=0;
for(int i=1;i<=50;i++){
int cnt=0;
bool flag=0;
for(int j=1;j<=n;j++){
if((a[j]>>(i-1))&1){
w[j]+=(1LL<<i-1);
if(w[j]==(1LL<<i-1))cnt++;
if(w[j]>(1LL<<i-1))flag=1;
}
}
if(!flag)ans+=cnt;
}
cout<<tot<<" "<<ans<<endl;
for(int i=1;i<=n;i++)w[i]=0;
}
}
return 0;
}