1. 程式人生 > 其它 >Deltix Round, Summer 2021 (open for everyone, rated, Div. 1 + Div. 2)B. Take Your Places!

Deltix Round, Summer 2021 (open for everyone, rated, Div. 1 + Div. 2)B. Take Your Places!

傳送門

首先顯然只要保留原數列的奇偶性,所以轉化成 $01$ 數列

分類討論最終情況

如果最終為 $010101...$ 的形式

直接貪心地想,第一個位置的 $0$ 肯定要從右邊最近的位置交換過來(反證法易證其最優性)

後面每個位置都是同理,要找到更後面最近的(因為前面已經處理完了

所以直接模擬這個貪心的過程即可,就是要注意程式碼實現的細節

當然,從右邊最近的位置交換過來時,別真的一個個相鄰的交換,這個一步即可模擬(程式碼裡會解釋)

如果貪心到一半發現找不到需要的 $0$ 或 $1$ 則說明無解

如果最終為 $1010..$ 的形式

也是同理處理,把原數列取反進行一遍完全一樣的操作即可

(這一題各種位運算真是煩死人了)

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
using namespace std;
const int N=2e5+7;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='
0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); } return x*f; } int t,n,a[N],b[N]; int work() { int l=1,r=2,ans=0; //l是當前處理到的位置,r是找需要的數的指標 while(l<=n) { if( a[l]^ (l&1) )//如果不滿足 10101... 的情況 { while( (!(a[r]^a[l])) && r<=n ) r++;//
找到後面第一個符合要求的數 if(r>n) return -1;//判斷邊界 swap(a[l],a[r]); ans+=r-l;//一次性交換 //因為區間 [l,r) 都是一樣的數 } l++; r=max(r,l+1); } return ans; } int main() { t=read(); while(t--) { n=read(); for(int i=1;i<=n;i++) a[i]=read()&1; for(int i=1;i<=n;i++) b[i]=a[i]; int ans=work(); for(int i=1;i<=n;i++) a[i]=b[i]^1;//取反再來一遍,注意覆蓋掉a陣列 int anss=work(); if(ans==-1) ans=anss; else if(anss!=-1) ans=min(ans,anss); printf("%d\n",ans); } return 0; }