题解 codeforces 1457-D Xor-gun

传送门


【题意】

初始给定长度为 \(n\),非递减的序列 \(\{a_n\}\) 。你可以进行操作,每次操作将两个相邻的数字消除,换为它们的异或和。问最少需要多少步使得原序列不再非递减。


【分析】

由于 \(a_i\leq 10^9\)\(2^{29}<10^9<2^{30}\)

故根据抽屉原理,当数量 \(n\geq 2\times 30+1=61\) 时,至少存在一个位数,使得以该位数为最高位的数字存在至少 \(3\) 个,且这 \(3\) 个数连续。

设上述的其中一组 \(3\) 个数在序列中位置分别为 \(a_{pos}, a_{pos+1}, a_{pos+2}\)

\(a_{pos+1}\otimes a_{pos+2}\) 的原最高位被异或消除,必定小于 \(a_{pos}\) ,则直接打破了非递减性。

因此,当 \(n\geq 61\) 时,答案为 \(1\)

\(n\leq 60\) 时,采用随机化的方式,取步数最少解。

当不存在该解时,直接输出 \(-1\)


【代码】

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll, ll> pii;
typedef double db;
#define fi first
#define se second
const int MAXN=1e5+10;
int n, a[MAXN], b[MAXN];
int main(){
    ios::sync_with_stdio(0);
    cin.tie(0); cout.tie(0);
    clock_t start = clock();
    cin>>n;
    for(int i=1;i<=n;++i) cin>>a[i];
    if(n>60)
        cout<<1;
    else{
        int ans=0;
        do{
            memcpy(b+1, a+1, sizeof(a[0])*n);
            int len=n;
            while(len>1){
                for(int i=1;i<len;++i)
                    if(b[i]>b[i+1]){
                        ans=max(ans, len);
                        break;
                    }
                --len;
                int pos=rand()%len+1;
                b[pos]^=b[pos+1];
                for(int i=pos+1;i<=len;++i)
                    b[i]=b[i+1];
            }
        }while( clock()-start<=1980 );
        if(ans) cout<<n-ans;
        else cout<<-1;
    }
    cout.flush();
    return 0;
}
posted @ 2021-06-22 22:24  JustinRochester  阅读(50)  评论(0编辑  收藏  举报