Codeforces #666 div2 A - D 解題報告
阿新 • • 發佈:2020-09-02
題目連結
A. Juggling Letters
題意:
給定 \(n\) 個字串,可以任意改變字元的位置(從一個字串插入到另一個字串的任意位置),問能否將 \(n\) 個字串變得一樣?
思路:
統計每個字元出現的次數,如果是 \(n\) 的倍數,那麼就可以均分,否則不行。
程式碼:
/* * @Author : nonameless * @Date : 2020-09-02 15:08:08 * @LastEditors : nonameless * @LastEditTime : 2020-09-02 15:16:36 */ #include <bits/stdc++.h> #define x first #define y second #define pb push_back #define sz(x) (int)x.size() #define all(x) x.begin(), x.end() using namespace std; typedef long long ll; typedef pair<ll, ll> PLL; typedef pair<int, int> PII; typedef pair<double, double> PDD; const double eps = 1e-6; const double PI = acos(-1.0); const int INF = 0x3f3f3f3f; const ll LNF = 0x3f3f3f3f3f3f; inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } inline ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } inline int lcm(int a, int b) { return a * b / gcd(a, b); } int cnt[30]; char s[1010]; int main(){ int t; scanf("%d", &t); while(t --){ memset(cnt, 0, sizeof cnt); int n; scanf("%d", &n); for(int i = 1; i <= n; i ++){ scanf("%s", s + 1); int len = strlen(s + 1); for(int j = 1; j <= len; j ++) cnt[s[j] - 'a'] ++; } int mark = 1; for(int i = 0; i < 26; i ++) if(cnt[i] % n){ mark = 0; break; } if(mark) puts("Yes"); else puts("No"); } return 0; }
B. Power Sequence
題意:
給定一個整數的數列。你可以通過以下兩種操作來使其變成一個等比數列(以1為首項)
- 可以任意交換兩個數的位置
- 花費1的代價使 \(a_i\) 變為 \(a_i + 1\) 或 \(a_i - 1\)
問最小代價可以是多少?
思路:
列舉公差 \(q\) 。
程式碼:
/* * @Author : nonameless * @Date : 2020-09-02 15:43:08 * @LastEditors : nonameless * @LastEditTime : 2020-09-02 16:26:15 */ #include <bits/stdc++.h> #define x first #define y second #define pb push_back #define sz(x) (int)x.size() #define all(x) x.begin(), x.end() using namespace std; typedef long long ll; typedef pair<ll, ll> PLL; typedef pair<int, int> PII; typedef pair<double, double> PDD; const double eps = 1e-6; const double PI = acos(-1.0); const int INF = 0x3f3f3f3f; const ll LNF = 0x3f3f3f3f3f3f; inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; } inline ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; } inline int lcm(int a, int b) { return a * b / gcd(a, b); } const int N = 1e5 + 10; int a[N]; int main(){ int n; scanf("%d", &n); for(int i = 1; i <= n; i ++) scanf("%d", a + i); sort(a + 1, a + n + 1); long long ans = LNF; for(int c = 1; ; c ++){ long long tmp = 0; long long s = 1; for(int i = 1; i <= n; i ++){ tmp += abs(a[i] - s); s *= c; if(s > 1e14) { tmp += ans; break; } } if(tmp > ans) break; ans = tmp; } cout << ans << endl; return 0; }
C. Multiples of Length
題意:
給定一個整數陣列,你要做三次操作使得陣列中的每個數都為零。
- 選定一段連續區間,設 $len = $ 區間長度,你可以使區間中的每個數都加上 \(len\) 的整數倍(包括負數)。
思路:
要在三次操作中解決,那麼顯然我們在兩次操作中要將區間 \([1, n]\) 的數都變為 \(n\) 的整數倍(第三次就可以完成要求),單獨對某個數來看有:\(a_i = a_i + k\times len\)。
要將 \(a_i\) 變為 \(n\) 的整數倍,顯然上式就應該出現 \(n\),那麼我們就必須考慮消去 \(a_i\),觀察可以發現當 \(len = n - 1, k = a_i\)
- 第一次操作區間為 \([1, n - 1]\),每個數加上 \(a_i\times(n- 1)\)。
- 第二次操作將 \(a_n\) 變為 0。
- 第三次操作區間為 \([1, n]\)。
程式碼:
/*
* @Author : nonameless
* @Date : 2020-09-02 18:50:52
* @LastEditors : nonameless
* @LastEditTime : 2020-09-02 19:00:13
*/
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const double eps = 1e-6;
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f;
inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
inline ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
inline int lcm(int a, int b) { return a * b / gcd(a, b); }
const int N = 1e5 + 10;
int a[N];
int main(){
int n; scanf("%d", &n);
for(int i = 1; i <= n; i ++) scanf("%d", a + i);
if(n == 1){
printf("1 1\n%d\n1 1\n0\n1 1\n0\n", -a[1]);
return 0;
}
printf("1 %d\n", n - 1);
for(int i = 1; i < n; i ++) printf("%lld ", 1ll * a[i] * (n - 1));
puts("");
printf("%d %d\n", n, n);
printf("%d\n", -a[n]);
printf("1 %d\n", n);
for(int i = 1; i < n; i ++) printf("%lld ", -1ll * a[i] * n);
puts("0");
return 0;
}
D. Stoned Game
題意:
有 \(n\) 堆石子,兩個人輪流每次取一顆,要求不能從上個人取的那堆裡取,取不到石子的人失敗,問在最優策略下,誰會獲勝?
思路:
- 考慮一種特殊情況,有一堆石子比其他堆加起來還多,那麼第一個取的人獲勝。
- 其他情況在最優策略下,肯定會取完所有的石子,那麼根據石子總數的奇偶就可以判斷,奇數先手贏,偶數後手贏。
程式碼:
/*
* @Author : nonameless
* @Date : 2020-09-02 19:22:54
* @LastEditors : nonameless
* @LastEditTime : 2020-09-02 19:24:45
*/
#include <bits/stdc++.h>
#define x first
#define y second
#define pb push_back
#define sz(x) (int)x.size()
#define all(x) x.begin(), x.end()
using namespace std;
typedef long long ll;
typedef pair<ll, ll> PLL;
typedef pair<int, int> PII;
typedef pair<double, double> PDD;
const double eps = 1e-6;
const double PI = acos(-1.0);
const int INF = 0x3f3f3f3f;
const ll LNF = 0x3f3f3f3f3f3f;
inline int gcd(int a, int b) { return b ? gcd(b, a % b) : a; }
inline ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
inline int lcm(int a, int b) { return a * b / gcd(a, b); }
int main(){
int t; scanf("%d", &t);
while(t --){
int n; scanf("%d", &n);
int mx = 0, sum = 0;
for(int i = 1; i <= n; i ++){
int x; scanf("%d", &x);
mx = max(mx, x);
sum += x;
}
if(mx > sum - mx || sum & 1) puts("T");
else puts("HL");
}
return 0;
}