題解 codeforces 1457-D Xor-gun
阿新 • • 發佈:2021-06-22
【題意】
初始給定長度為 \(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; }