給定一組共 n 個資料 ,如果倆個數的下標在 mod k 意義下同餘,則可以交換a[I] 和 a[j] ,求操作後一段連續的數的和的最大值。
本題屬於水題,因為 t 和 n 都比較小,所以可以直接暴力的把所有最大的數移到最前面的 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;
}
讀題速度要快,儘早秒殺。
有 n 個選手舉辦羽毛球比賽,總共比 n-1 場,每個人不是贏了 x 場就是贏了 y 場,要求構造
一組合理的每場獲勝選手的資料。
這是一道考研思維的題,我們可以結合生活實際,首先了解比賽的規則。
比賽必須有輸有贏,所以 x 和 y 中必須有一個大於 0 ,一個等於 0 (因為總會有人輸,也有人贏)。
因為總共比 n-1 場,而贏得人都贏了 x 或 y 次,所以要求 (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;
}
給定一組非負整數,可以最多進行 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的前三題相對簡單,想要快速解決,應該多加鍛鍊思維能力(多打比賽)。