Codeforces Global Round 18 A-C題解
csdn轉過來的,我是yzh本人,不是抄的文章
A. Closing The Gap
題意:
給$n$個整數$a_1$...$a_n$,有一種操作:
選擇兩個a,b使a+=1,b-=1
問經過若干次操作後,$Max(a_i...a_n)-Min(a_i...a_n)$的最小值
思路:
想水流一樣,這個高度差的最小值不可能>1(可自行證明)
如果$\sum_{i=1}^n a_i$ $mod$ $n$為0那麼直接輸出0
若不為0則輸出1
程式碼:
#include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<cstdio> using namespace std; #define int long long int t,n,ans; signed main(){ cin>>t; while(t--){ cin>>n; ans=0; for(int i=1;i<=n;++i){ int a; cin>>a; ans+=a; } if(ans%n==0) puts("0"); else puts("1"); } return 0; }
B. And It's Non-Zero
題意:
給定$l$和$r$,數列為$l...r$,問至少刪除多少個元素可以使按順序進行與(&)運算的結果不為0
思路:
居然只要不為0就可以那我們只要確定$l...r$的數轉換成二進位制中,1最多的那一位,然後用數列中數的個數減去這一位的個數。例如:
l=1,r=4
那麼轉換成二進位制就是:
4:1 0 0
3:0 1 1
2:0 1 0
1:0 0 1
定義記錄一的陣列為sum,則:
sum:1 2 2
輸出結果為4-2=2
所以只管留最多1的位就是最優解。
程式碼:
#include<iostream> #include<algorithm> #include<cstring> #include<cmath> #include<cstdio> using namespace std; int T,l,r; int sum[200010][25]; int main(){ // scanf("%d",&T); cin>>T; for(int i=1;i<=200000;++i){ for(int j=1;j<=25;++j){ sum[i][j]=sum[i-1][j]; } int it=i; int jt=0; while(it){ ++jt; sum[i][jt]+=(it%2); it/=2; } } while(T--){ // scanf("%d%d",&l,&r); cin>>l>>r; int maxn=-1; for(int i=1;i<=25;++i){ maxn=max(maxn,sum[r][i]-sum[l-1][i]); } // printf("%d\n",(r-l+1)-maxn); cout<<(r-l+1)-maxn<<endl; } return 0; }
注意預處理的過程不要卡陣列的線,要不然會導致一直亂輸出
(昨天就因為這個調了半天)
C. Menorah
題意:
給兩個長度為$n$的字串a和b,給定一種操作:
固定a中一個‘1’,將其他字元反轉(0變1,1變0)
問至少進行多少次操作可以使字串a變成b。
思路:
我們不難發現,每進行兩次操作我們其實都是交換了一對1和0
證明:
若第一次操作選擇了第i位的1,那麼第二次再選擇第i位就是無意義的操作
第二次操作選擇第j位的1,由於在第一次操作前第j位為0,也就是說,將操作後的第j位保留了下來,而其他反轉
反轉過後除了第i位都回歸第一次操作前,而第i位變成了0
也就是說將一對1和0進行了交換
然後我們定義三個陣列:
sumb為陣列b中‘1’的個數,suma同理,dif為a和b有幾位不同
若$sumb=suma$我們可以直接從a交換到b,輸出答案為dif
然後我們發現倒數第二個樣例過不了(不得不說這次出的樣例是真的良心),通過樣例解釋我們發現,可以將字串a轉換到除了第i位與b第i位都為1外其他任意一位都不相等(詳情見cf),那麼我們只需要固定第i位做一次操作即可,所以我們得出來下面一種可行的方案:
若n-suma==sumb-1(若成立則可以通過若干次操作後得到”字串a轉換到除了第i位與b第i位都為1外其他任意一位都不相等“這樣一個串,然後固定一個1反轉即可)
這種情況下答案就是(n-1)-dif+1
解釋:第一個(n-1)-dif是指保留一位與b串相等的情況下把其他位都變為不等的操作次數,最後+1是最後的一次操作
程式碼:
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<cstdio>
using namespace std;
const int inf=0x3f3f3f3f;
int T,n,suma,sumb,dif,ans;
string a,b;
int main(){
// scanf("%d",&T);
cin>>T;
while(T--){
// scanf("%d",&n);
cin>>n;
cin>>a>>b;
ans=inf;
suma = sumb = dif = 0;
for(int i=0;i<n;++i){
if(b[i]=='1') sumb++;
if(a[i]=='1') suma++;
if(a[i]!=b[i]) dif++;
}
if(suma==sumb){
ans=min(ans,dif);
}
if(n-suma==sumb-1){
ans=min(ans,n-dif);
}
if(ans==inf){
puts("-1");
}
else printf("%d\n",ans);
}
return 0;
}