Codeforces Round #836 (Div. 2) A-D題解
A、SSeeeeiinngg DDoouubbllee
一個字串的每個字母翻倍,且沒有其他限制。所以把字串正著輸一遍,再倒敘輸出一遍即可。
點選檢視程式碼
#include <bits/stdc++.h> using namespace std; #define N 100010 template <class T> inline void read(T& a){ T x = 0, s = 1; char c = getchar(); while (!isdigit(c)){ if(c == '-') s = -1; c = getchar(); } while(isdigit(c)){ x = x * 10 + (c ^ '0'); c = getchar(); } a = x * s; return ; } int main(){ int T; read(T); while(T--){ string s; cin >> s; cout << s; for(int i = s.length()-1; i >= 0; i--) cout << s[i]; cout << endl; } return 0; }
B、XOR = Average
對於奇數個的非常好想。全部輸出 \(1\) 時可以發現剛好全部相等。
對於偶數個時,如下考慮:先將前 \(n - 2\) 個設為相同的某個數 \(x\),那麼原式即為: \(a_1\) ^ \(a_2\) \(=\) \(\dfrac{(a_1 + a_2 + (n - 2) * x)}{n}\)。化簡,可以變成:
\(n(a_1\) \(xor\) \(a_2) = a_1 + a_2 - 2x + nx\)。所以得到: \(a_1\) \(xor\) \(a_2 = x\) 且 \(a_1 + a_2 = 2x\)。枚舉發現,\(a_1 = 1, a_2 = 3, x = 2\)
點選檢視程式碼
#include <bits/stdc++.h> using namespace std; #define N 100010 int main(){ int T; cin >> T; while(T--){ int n; cin >> n; if(n % 2 == 1){ for(int i = 1; i <= n; i++) cout << 1 << " "; } else{ for(int i = 1; i <= n - 2; i++) cout << 2 << " "; cout << "1 3"; } cout << endl; } return 0; }
C、Almost All Multiples
首先一個顯然的結論,當且僅當 \(n\) 是 \(k\) 的倍數的時候,才存在這樣的排列。反證:若將另外一個倍數放過來,則 \(n\) 也必定不能放在另外那個倍數的位置上。所以 \(n\) 不是 \(k\) 的倍數的時候,就不存在。
接著,先考慮一個通解:收尾按照要求放好,剩下的每個位置先放上自己,第 \(k\) 位則特殊地放 \(n\)。可以發現,對於 \(k\) 前面的位置,已經達到了字典序最優。所以考慮把 \(n\) 嘗試往後移動。考慮 \(O(N)\) 做法:每次向後走,遇到一個數字,如果他恰好是 \(k\) 的倍數,而且 \(n\) 也是他的倍數,那麼證明二者可以交換。值得注意的是,\(n\) 是所有數字中最大的,且我們優先變換較小的數字,所以這次操作對於字典序一定最優。
點選檢視程式碼
#include <bits/stdc++.h>
using namespace std;
#define N 1000010
int n, k;
int ans[N];
int main(){
int T; cin >> T;
while(T--){
cin >> n >> k;
if(n % k != 0) puts("-1");
else{
ans[1] = k;
ans[n]= 1;
for(int i = 2; i < n; i++){
if(i != k) ans[i] = i;
else ans[i] = n;
}
ans[n] = 1;
int now = k;
for(int i = k + 1; i < n; i++){
if(n % i == 0 && i % now == 0){
swap(ans[now], ans[i]);
now = i;
}
}
for(int i = 1; i <= n; i++)
cout << ans[i] << " ";
cout << endl;
}
}
return 0;
}
D、Range = √Sum
一道純純的構造題。對於 \(n\) 為偶數的情況,發現在以 \(n\) 為中心,半徑為 \(/dfrac{n}{2}\) 的去心鄰域內,所有整陣列成的數列合法。
對於 \(n\) 為奇數的情況,如此考慮。先考慮以 \(n\) 為中心,半徑為 \(/dfrac{n}{2}\) (向下取整) 的鄰域中的所有連續整數,則有差值:\(n-1\)。和: \(n^2\)。
去掉根號,有:\(n^2 - 2n = 1\) 與 \(n^2\)。可以發現,最大與最小的值一個加一一個減一,和不變,但可以把差值變為 \(n^2 + 2n + 1\)。總體右移,總和增大 \(2n\),倒數第二個右移一位,總和加一。可以發現此時二者相等。
點選檢視程式碼
#include <bits/stdc++.h>
using namespace std;
#define N 100010
int main(){
int T; cin >> T;
while(T--){
int n; cin >> n;
if(n % 2 == 0){
for(int i = n / 2; i <= n * 3 / 2; i++){
if(i != n) cout << i << " ";
}
}
else{
vector <int> G;
for(int i = n - (n / 2); i <= n + (n / 2); i++)
G.push_back(i);
for(int i = 0; i < G.size(); i++)
G[i] += 2;
G[0] -= 1;
G[G.size()-1] += 1;
G[G.size()-2] += 1;
for(auto it : G){
cout << it << " ";
}
}
cout << endl;
}
return 0;
}