Codeforces Round 983 (Div. 2) 題解
Codeforces Round 983 (Div. 2)
Problem - A - Codeforces
解題思路
- 考慮貪心,每個燈連兩個開關,即兩個開的燈可以關閉一盞燈,則燈數最多則儘可能讓兩個開關都開的燈儘量少,燈數最少則反之
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
int a[110];
void solve(){
int n;cin>>n;
int cnt0=0,cnt1=0;
for(int i=1;i<=2*n;i++){
int x;cin>>x;
if(x==1) cnt1++;
else cnt0++;
}
int ans1=0,ans2=0;
if(cnt1<=n) ans1=cnt1;
else ans1=n-(cnt1-n);
ans2=cnt1%2;
cout<<ans2<<" "<<ans1<<endl;
}
int main(){
std::ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T;cin>>T;
while(T--) solve();
return 0;
}
Problem - B - Codeforces
解題思路
- 構造,我們可以考慮這樣一個構造,將陣列分成三段,第k個數為中間一段,並且令k為中位數,這樣的話,加上前後的陣列則滿足題目意思
- 注意特判n=1時直接輸出1,k=1或k=n時輸出-1
- k要分奇偶討論,如果k為偶數則[1,k-1],[k,k],[k+1,n];如果k為奇數則[1,k-2],[k-1,k+1],[k+2,n]
#include<bits/stdc++.h>
#define endl '\n'
using namespace std;
const int N=2e5+10;
int a[N];
void solve(){
int n,k;cin>>n>>k;
if(n==1){
cout<<1<<endl;
cout<<1<<endl;
return;
}
if(k==1 || k==n){
cout<<-1<<endl;
return;
}
if(k%2==0){
cout<<3<<endl;
cout<<1<<" "<<k<<" "<<k+1<<endl;
}
else{
cout<<3<<endl;
cout<<1<<" "<<k-1<<" "<<k+2<<endl;
return;
}
}
int main(){
std::ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T;cin>>T;
while(T--) solve();
return 0;
}
Problem - C - Codeforces
解題思路
- 要滿足a[i]+a[j]>a[k],那麼假如我們讓最小的兩個值相加能大於陣列裡的最大值,則一定可以滿足,不妨排序一下,我們二分第一個大於a[1]+a[2]的位置id,則我們只需更改n-id+1個數則可以滿足題意
- 但上述不一定是最少的操作次數,因為我們也可以透過更改a[1]或者a[2]使得滿足題意思,如果我們更改a[1],a[2]的值,我們一定能讓其中一個數與其他數的和都能滿足題意
- 所以我們可以將題意簡化成,我們每次刪除一個數字,使得所有的a[i]+a[j]>a[k],(因為我們最多對一個數操作一次賦值,並且他與其他數的和一定滿足題意)
- 所以列舉a[i],二分第一個大於a[i]+a[i+1]的位置id,ans即為(i-1)+(n-id+1)
- 時間複雜度為O(nlogn)
#include<bits/stdc++.h>
#define endl '\n'
#define int long long
using namespace std;
const int N=2e5+10;
int a[N];
void solve(){
int n;cin>>n;
for(int i=1;i<=n;i++) cin>>a[i];
sort(a+1,a+n+1);
int ans=1e9;
for(int i=1;i<=n-1;i++){
int x=a[i]+a[i+1];
int id=lower_bound(a+1,a+n+1,x)-a;
int tmp=n-id+1+i-1;
// cout<<x<<" "<<id<<" "<<tmp<<endl;
ans=min(ans,tmp);
}
cout<<ans<<endl;
}
signed main(){
std::ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T;cin>>T;
while(T--) solve();
return 0;
}
Problem - D - Codeforces
解題思路
- 感覺難點在於讀題,題目的三條性質其實表示這是一顆層序遍歷的樹,除0點外每一個節點只有一個孩子
- 我們可以透過一個佇列進行模擬詢問,只要找出節點1的孩子之後剩下的就依次詢問即可
- 詳情見程式碼部分
#include<bits/stdc++.h>
using namespace std;
const int N=1e4+10;
int fa[N];
int ask(int x,int y){
cout<<"? "<<x<<" "<<y<<endl;
int tmp;cin>>tmp;
return tmp;
}
void solve(){
int n;cin>>n;
fa[1]=0;
queue<int> q;
q.push(1);
int now=2;
while(now<n){
int tmp=ask(1,now);
if(tmp==1){
fa[now]=0;
q.push(now);
now++;
}
else if(tmp==0){
fa[now]=1;
q.pop();//1出隊
q.push(now);
now++;
break;
}
}
while(now<n){
int t=q.front();
q.pop();
int tmp=ask(t,now);
if(tmp==0){
fa[now]=t;
q.push(now);
now++;
}
}
cout<<"! ";
for(int i=1;i<n;i++) cout<<fa[i]<<" ";
cout<<endl;
}
int main(){
std::ios::sync_with_stdio(false);
cin.tie(0);cout.tie(0);
int T;cin>>T;
while(T--) solve();
return 0;
}