Codeforces Round #821(Div.2) (A-C) 題解

2022-09-20 21:00:39

Codeforces Round #821(Div.2) (A-C)  

A.Consecutive Sum

大致題意

給定一組共 n 個資料 ,如果倆個數的下標在 mod k 意義下同餘,則可以交換a[I]a[j] ,求操作後一段連續的數的和的最大值。

基本思路

本題屬於水題,因為 tn 都比較小,所以可以直接暴力的把所有最大的數移到最前面的 k 個位置,即從最後 k 個數開始向前列舉比較,做氣泡排序即可。

程式碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=105;
ll a[N];

int main(){
	int T;
	cin>>T;
	while(T--){
		memset(a,0,sizeof a);
		
		int n,k;
		cin>>n>>k;
		for (int i=1;i<=n;i++){
			cin>>a[i];
		}
		
		for (int i=1;i<=k;i++){
			for (int j=n-i+1;j>=1+k;j-=k) {
				if (a[j]>a[j-k]) swap(a[j],a[j-k]);
			}
		}
		
		ll ans=0;
		for (int i=1;i<=k;i++) ans+=a[i];
		cout<<ans<<endl;
		
	}
	
	return 0;
	
}

建議

讀題速度要快,儘早秒殺。


B.Rule of League

大致題意

n 個選手舉辦羽毛球比賽,總共比 n-1 場,每個人不是贏了 x 場就是贏了 y 場,要求構造

一組合理的每場獲勝選手的資料。

基本思路

這是一道考研思維的題,我們可以結合生活實際,首先了解比賽的規則。

比賽必須有輸有贏,所以 xy 中必須有一個大於 0 ,一個等於 0 (因為總會有人輸,也有人贏)。

因為總共比 n-1 場,而贏得人都贏了 xy 次,所以要求 (n-1) mod max(x,y)=0 ,即贏的人的獲勝場次必須是 n-1 的因子。

綜上,可以得到三個不存在合理資料的條件,可以由此特判輸出 -1

接著,對於合理的資料,只要從 1 開始列舉獲勝者的編號即可,如果害怕列舉出錯,可以模擬比賽

過程,列舉當前場次的對手,這樣獲勝者的座標不會出錯且時間複雜度不變。

程式碼如下。

程式碼

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int main() {
	int t;
	cin>>t;
	while(t--) {
		int n,x,y;
		cin>>n>>x>>y;
		ll ans=0;
		int p=n-1;
		ll nowx=max(x,y),nowy=min(x,y);

		if (nowy!=0 || nowx+nowy==0 || p%nowx!=0) {
			puts("-1");
			continue;
		}

		int i;
		int tot=1,k=2;  //用k模擬對手
		for (i=1; i<=p;) {
			for (int j=1; j<=nowx; j++) {
				cout<<tot<<" ";
				k++;
			}
			i=i+nowx;
			tot=k;
		}
		cout<<endl;

	}
	return 0;
}

C.Parity Shuffle Sorting

大致題意

給定一組非負整數,可以最多進行 n 次操作,選取倆個數,當倆個數之和為奇數,可以把右邊的數變成左邊的數;如果是偶數,可以將左邊的數變成右邊的數。要求經過操作後得到一組非遞減序列。

基本思路

依舊是一道思維題。

由於倆數之和為奇數時,右邊的數可以變成左邊的數,所以顯然,每個與第一個數之和為奇數的數可以變成第一個數;反之,每個與最後一個數之和為偶數的數可以變成最後一個數。由此可得:每個數都可以變成第一個數或者最後一個數。

除此之外,根據操作規則,我們也能把第一個數變成最後一個數,或者把最後一個數變成第一個數。將頭尾倆數變成同一個數之和,便可以將每個數都變成同一個數,操作次數最多為 n-1 次,即單組資料時間複雜度為 O(n)

需要注意的是,當 n=1 時,無需操作,可直接輸出 0 ;整個程式時間複雜度為 O(n*t) ,因為倆個數最大都為 1e5 所以不能用 memset 函數初始化陣列,不然會超時。(實際上也不需要初始化)

程式碼如下

程式碼

#include<bits/stdc++.h>
using namespace std;
const int N=100005;
typedef long long ll;
ll a[N];
int l[N],r[N];
int main() {
	int T;
	cin>>T;
	while(T--) {
		int n;
		cin>>n;
		for (int i=1; i<=n; i++) cin>>a[i];
		int cnt=0;
		
		if (n==1){
			puts("0");
			continue;
		}
		
		if (a[1]!=a[n]) {

			if (a[1]%2==1 && a[n]%2==0) {
				l[++cnt]=1;
				r[cnt]=n;
				a[n]=a[1];
			} else if (a[1]%2==1 && a[n]%2==1) {
				l[++cnt]=1;
				r[cnt]=n;
				a[1]=a[n];
			} else if (a[1]%2==0 && a[n]%2==0) {
				l[++cnt]=1;
				r[cnt]=n;
				a[1]=a[n];
			} else {
				l[++cnt]=1;
				r[cnt]=n;
				a[n]=a[1];
			}

		}

		for (int i=2; i<=n-1; i++) {
			int now=a[i]+a[1];
			if (now%2==0) {
				l[++cnt]=i;
				r[cnt]=n;
			} else {
				l[++cnt]=1;
				r[cnt]=i;
			}
		}
		
		cout<<cnt<<endl;
		for (int i=1; i<=cnt; i++) cout<<l[i]<<" "<<r[i]<<endl;

	}

	return 0;
}

總結

Codeforces 的比賽前三題主要重視的是思維而非演演算法,並不能讀完題就思考用什麼演演算法解決問題,且題目的真意常常不如題面上描述的複雜,所以應該藉助樣例,探究其中的規律,瞭解題目的真實意圖,這一點與 OI 注重演演算法思維的比賽有些許不同。

除此之外,由於有時不能直接借用某種演演算法來解決問題,所以還要會精確地計算時間複雜度,避免超時。當然,由於有可能被其他選手 hack ,在考慮問題的時候需要注意某些特別的資料。

總體而言,div.2的前三題相對簡單,想要快速解決,應該多加鍛鍊思維能力(多打比賽)。