【Codeforces Round #655 (Div. 2)】A-D
Codeforces Round #655 (Div. 2)
A. Omkar and Completion
題意
給出一個整數 n ,讓構造出一個長度為 n 的陣列,使得不存在\(1\leq x,y,z\leq n\),滿足\(a_x+a_y=a_z\)。
思路
直接輸出 n 個 1
程式碼
#include <bits/stdc++.h> #define fuck system("pause") #define emplace_back push_back #define pb push_back using namespace std; typedef long long ll; const int mod = 1e9 + 7; const double eps = 1e-6; const int inf = 0x3f3f3f3f; const int N = 2e5 + 10; int main() { int T; scanf("%d", &T); while(T--){ int n; scanf("%d", &n); for (int i = 1; i <= n;i++){ printf("1 "); } printf("\n"); } // fuck; return 0; } /* */
B. Omkar and Last Class of Math
題意
給出一個整數 n ,讓找出兩個整數 a , b ,滿足 a + b = n ,並且 LCM(a,b) 最小。
思路
先猜一下,偶數應該直接輸出兩個半值。
直接打了個表:
找出其最小的素因子 p ,輸出 n / p , n - n / p。
程式碼
#include <bits/stdc++.h> #define fuck system("pause") #define emplace_back push_back #define pb push_back using namespace std; typedef long long ll; const int mod = 1e9 + 7; const double eps = 1e-6; const int inf = 0x3f3f3f3f; const int N = 2e5 + 10; int main() { int T; scanf("%d", &T); while (T--) { int n, flag = 0; scanf("%d", &n); for (int i = 2; i * i <= n; i++) { if (n % i == 0) { flag = i; break; } } if (!flag) { printf("%d %d\n", 1, n - 1); } else { printf("%d %d\n",n/flag, n-n/flag); } } // fuck; return 0; }
C. Omkar and Baseball
題意
給出一個長度為 n 的全排列,現在定義一種特殊的交換:
你可以選擇一個連續的子陣列,任意排放其中元素的位置,只需保證每個元素都不在本來的位置。
問最少需要多少次排列使得其遞增。
思路
首先可以知道最多隻需要排兩次。
如果本來遞增,那麼不需要排。
如果只有一段連續的子陣列,每個元素都不在其位置上( i 不在第 i 個位置),那麼只需要一次。
有兩段或者多段,那麼第一次選擇整個陣列進行打亂,第二次維護成遞增
程式碼
#include <bits/stdc++.h> #define fuck system("pause") #define emplace_back push_back #define pb push_back using namespace std; typedef long long ll; const int mod = 1e9 + 7; const double eps = 1e-6; const int inf = 0x3f3f3f3f; const int N = 2e5 + 10; int arr[N]; int main() { int T; scanf("%d", &T); while (T--) { int n; scanf("%d", &n); int flag = 1, num = 0; for (int i = 1; i <= n; i++) { scanf("%d", &arr[i]); if (arr[i] < arr[i - 1]) { flag = 0; } } if (flag) { printf("0\n"); continue; } int pre, nex; for (int i = 1; i <= n; i++) { if (arr[i] != i) { pre = i; break; } } for (int i = n; i; i--) { if (arr[i] != i) { nex = i; break; } } for (int i = pre; i <= nex; i++) { if (arr[i] == i) { flag = 1; break; } } if (flag) { printf("2\n"); } else printf("1\n"); } // fuck; return 0; } /* */
D. Omkar and Circle
題意
給出一個長度為 n(奇數) 的迴圈陣列(首尾相連),現在每次可以選擇兩個相距為 2 的數字,用他倆的和替代中間的數字。
操作到最後,只剩下一個數字,問這個數字最大是多少。
思路
本質就是刪除 n / 2 個數字後最大的和。
刪除的時候要滿足這些數字不能相鄰。
試著刪一下就可以發現:
無論怎麼刪除都會存在兩個連續的數字沒有被刪除,這兩個數字相鄰的必定被刪除,其他的數字隔一個刪一個。
所以我們可以列舉這兩個沒有被刪除的數字。
維護兩個陣列 pre , suf 。
\(pre_i\)表示以第 i 個為結尾的隔一個刪一個的被刪除的和。
\(suf_i\)表示以第 i 個為開頭的隔一個刪一個的被刪除的和。
對於以第 i , i + 1 沒有被刪除,其剩餘的和為 \(sum - pre_i - suf_{i+2}\)。
注意特判第 1 個和最後 1 個以及倒數第一個倒數第二個沒被刪除。
程式碼
#include <bits/stdc++.h>
#define fuck system("pause")
#define emplace_back push_back
#define pb push_back
using namespace std;
typedef long long ll;
const int mod = 1e9 + 7;
const double eps = 1e-6;
const ll inf = 0x3f3f3f3f3f3f3f3f;
const int N = 2e5 + 10;
int arr[N];
ll pre[N], suf[N];
int main()
{
int n;
ll sum = 0;
scanf("%d", &n);
for (int i = 1; i <= n;i++){
scanf("%d", &arr[i]);
sum += arr[i];
}
pre[1] = arr[1], suf[n] = arr[n];
for (int i = 2; i <= n;i++){
pre[i] = pre[i - 2] + arr[i];
}
for (int i = n - 1; i;i--){
suf[i] = suf[i + 2] + arr[i];
}
ll ans = inf;
for (int i = 1; i < n - 1; i++) {
ans = min(ans, pre[i - 1] + suf[i + 2]);
}
ans = min(min(pre[n - 1], pre[n - 2]), ans);
printf("%lld\n", sum - ans);
// fuck;
return 0;
}
/*
*/