1. 程式人生 > 其它 >題解 codeforces 1457-D Xor-gun

題解 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;
}