牛客多校2022 2

牛客多校2022 2

\(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;
} 
posted @ 2022-08-01 18:02  Xu-daxia  阅读(39)  评论(0编辑  收藏  举报