配置檔案初始化異常Configuration system failed to initialize
目錄
Codeforces Round #655 (Div. 2)
1. 題目分析
- A: 思維題,構造性題目
- B: 打表發現規律
- C: 思維
- D: 思維+dp
- E:
- F:
2. 題解
A. Omkar and Completion
題意: 給定t個測試樣例,每個測試樣例給定一個n,要求構造一個長度為n的數列,數列中任意兩個數字相加不會等於數列中其他的數字。t~1e3, n~1e3
題解:
程式碼:
#include <bits/stdc++.h> using namespace std; int main() { int T, n; cin >> T; while (T--) { cin >> n; for (int i = 1; i <= n; ++i) { cout << 1 << " "; } cout << endl; } return 0; }
B. Omkar and Last Class of Math
題意: 給定一個n,可以把n拆解成a、b,使得a+b=n,求使得lcm(a, b)最小的a和b。n~1e9
題解: 打表發現,如果n是偶數,那麼直接輸出n/2 n/2;如果n是奇數,那麼去找n的最大奇數因數a,輸出a n-a
程式碼
#include <bits/stdc++.h> using namespace std; int main() { int T; cin >> T; for (int i = 1, a; i <= T; ++i) { scanf("%d", &a); if (a % 2 == 0) { cout << a / 2 << " " << a / 2 << endl; } else { int maxv = 1; for (int i = 2; i <= a / i; ++i) { if (i % 2 == 0) continue; if (a % i == 0 && (i > maxv || a / i > maxv)) { if (i > maxv) maxv = max(maxv, i); if (a / i > maxv) maxv = max(maxv, a / i); } } cout << maxv << " " << a - maxv << endl; } } return 0; }
C. Rational Ratio
題意: 定義一種交換:選擇一段區間[l, r], 一次交換把[l, r]上的所有數改變位置(每個數字都必須改變位置),問把一個任意數列變成有序數列(a[i]=i),需要多少次這樣的交換。數列個數2e5,a[i]~1e18
題解: 分析可知交換隻有0,1,2三種情況,如果一開始就是有序的,輸出0;一開始無序的段只有1個(無序的段意思是這個段內每個數字a[i] != i),那麼輸出1;否則輸出2(如果無序的段有多個,可以把所有無序的段加上中間有序的看作一整個無序的段,然後通過1次交換,使得每個數字都不在原來的位置上,在進行一次交換都回到自己的位置上即可)
程式碼:
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int const N = 2e5 + 10;
LL a[N];
int T, n;
int main() {
cin >> T;
while (T--) {
cin >> n;
for (int i = 1; i <= n; ++i) scanf("%lld", &a[i]);
int sorted = 1, rand_cnt = 0, contient = 1;
for (int i = 1; i <= n; ++i) {
if (a[i] != i) {
sorted = 0;
if (contient) {
rand_cnt ++;
contient = 0;
}
}
if (a[i] == i) {
contient = 1;
}
}
if (sorted) {
cout << 0 << endl;
continue;
}
else if (rand_cnt == 1) {
cout << 1<< endl;
continue;
}
else cout << 2<< endl;
}
return 0;
}
D. Omkar and Circle
題意: 給定n個數字,這n個數字都在一個圓上,每次可以選擇3個數字,刪掉這3個數字,把左右兩邊的數字的和賦值給中間的數字。最後圓上只會剩下一個數字,求剩下的數字的最大值。
題解: 選擇3個數字,刪掉這3個數字,把左右兩邊的數字賦值給中間的數字,這樣的操作對於最後的答案來說,就是刪掉中間那個數字。則n個數字,需要刪掉n/2個數字,剩下n/2+1個數字。可以證明被刪掉的數字一定是間隔的,因為如果不是間隔的,一定可以證明為間隔刪更小。既然刪掉n/2個數組,同時是間隔的,那麼剩下的數字有兩個數字是相鄰的,其他都是間隔的。可以選擇去列舉這兩個相鄰的數字,使用dp即可。li[i]維護從i往前,間隔的數字字首和;re[i]維護從i往後,間隔的數字字尾和。不斷列舉li[i]+re[i]的和最大值即可。
程式碼
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
int const N = 2e5 + 10;
LL le[N], ri[N];
int n, a[N];
int main() {
cin >> n;
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
if (n == 1) {
cout << a[1] << endl;
return 0;
}
for (int i = 1; i <= n; ++i) {
if (i >= 2) le[i] = le[i - 2] + a[i];
else le[i] = a[i];
}
for (int i = n; i >= 1; --i) {
if (i <= n - 1) ri[i] = ri[i + 2] + a[i];
else ri[i] = a[i];
}
LL res = -1;
for (int i = 1; i <= n - 1; ++i) {
res = max(res, le[i] + ri[i + 1]);
}
res = max(res, le[n]);
cout << res << endl;
return 0;
}