比赛链接:
https://vjudge.net/contest/226750
A - Peak
题目大意:
判断序列是不是先严格单调递增,后严格单调递减。
思路:
先前往后找递增的,然后后往前找递增的,判断位置是不是一样且在 2 ~ \(n - 1\) 上就行。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL T, n;
void solve(){
cin >> n;
vector <LL> a(n + 1);
for (int i = 1; i <= n; ++ i)
cin >> a[i];
LL p = 1, q = n;
while ( p < n && a[p] < a[p + 1] ) p++;
while ( q > 1 && a[q - 1] > a[q] ) q--;
if (p == 1 || q == n) cout << "No\n";
else if (p == q) cout << "Yes\n";
else cout << "No\n";
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
cin >> T;
while (T--)
solve();
return 0;
}
B - King of Karaoke
题目大意:
给定两个序列 \(a\),\(b\),可以让序列 \(a\) 的每一个元素加上 \(k\),判断最多能让多少 \(a_i == b_i\),输出数量。
思路:
因为所有元素加上一个值后,不会改变一个序列内所有元素间的差值,所以直接让两个序列做差,判断哪个数数量最多就行。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL T, n, x;
void solve(){
cin >> n;
LL ans = 0;
map <LL, LL> cnt;
vector <LL> a(n + 1), b(n + 1);
for (int i = 1; i <= n; ++ i)
cin >> a[i];
for (int i = 1; i <= n; ++ i)
cin >> b[i];
for (int i = 1; i <= n; ++ i){
x = a[i] - b[i];
cnt[x]++;
}
for (auto i : cnt)
ans = max(ans, i.second);
cout << ans << "\n";
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
cin >> T;
while (T--)
solve();
return 0;
}
D - Sequence Swapping
题目大意:
给定一个长为 \(n\) 的括号序列 \(s\),每一个括号有一个权值 \(a\),可以交换邻近的两个合法括号,即 \(s[i]\) = '(', \(s[i + 1]\) = ')',交换后获得 \(a[i] * a[i + 1]\) 的分数,求出能获得的最大分数。
思路:
因为交换了一对合法括号后,不会改变同一类型的括号的相对位置,即没有后效性,所以可以想到 \(dp\)。
定义 \(dp[i][j]\) 为第 \(i\) 个左括号移动到第 \(j\) 个位置及其右边的最大值。
先求一下每一个左括号与后面的右括号交换后得到的分数,放到 \(dp\) 数组中。
接着 \(dp\),\(dp[i][j]\) 的值就是从前面所有的左括号的最大值加上自己得到的,即 \(dp[i][j] += max(\sum_{k = 1}^{cnt} dp[k][j])\)。
所有最大值的答案都被转移到 \(dp[n]\) 中,求出该行的最大值,就是答案。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 1e3 + 10;
LL T = 1, n, dp[N][N];
char s[N];
void solve(){
cin >> n >> (s + 1);
vector <LL> a(n + 1);
for (int i = 1; i <= n; ++ i)
cin >> a[i];
memset ( dp, 0, sizeof dp);
for (int i = 1; i <= n; ++ i)
if (s[i] == '(')
for (int j = i + 1; j <= n; ++ j)
dp[i][j] = dp[i][j - 1] + ( s[j] == ')' ? a[i] * a[j] : 0);
for (int i = 1; i <= n; ++ i){
LL mx = 0;
for (int j = 1; j <= n; ++ j){
mx = max( mx, dp[i - 1][j]);
dp[i][j] += mx;
}
}
LL ans = 0;
for (int j = 1; j <= n; ++ j)
ans = max( ans, dp[n][j]);
cout << ans << "\n";
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
cin >> T;
while (T--)
solve();
return 0;
}
J - CONTINUE...?
题目大意:
给一个长为 \(n\) 的 01 字符串,第 \(i\) 位的同学有 \(i\) 个宝石,0 表示这个人是女生,1 表示他是男生,现在将女生分成两组 \(G1\) 和 \(G2\),男生分成 \(G3\) 和 \(G4\),找到一种方案,让 \(G1 + G3\) 的宝石和 \(G2 + G4\) 的宝石数量相同,找不到输出 -1.
思路:
由两组的宝石数量相同可以得到,宝石的总数量要为偶数,即 \(( (n + 1) * n / 2 ) % 2 == 0\)。
接下来只需要让找到方案等于总数的一半就行,直接遍历去找就好了,将所有人分成两组,每组再判断是不是男女,输出对应的组就行了。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL T, n;
string s;
void solve(){
cin >> n >> s;
LL k = n * (n + 1) / 2;
vector <LL> v(n + 1);
if (k % 2 == 0){
k /= 2;
for (LL i = n; i; -- i){
if ( k >= i ){
k -= i;
v[i] = 1;
}
}
for (int i = 1; i <= n; ++ i){
if (v[i]){
if (s[i - 1] == '1') cout << 3;
else cout << 1;
}
else {
if (s[i - 1] == '1') cout << 4;
else cout << 2;
}
}
cout << "\n";
}
else cout << "-1\n";
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
cin >> T;
while (T--)
solve();
return 0;
}
K - Mahjong Sorting
题目大意:
一副麻将,\(C\)(万)、\(B\)(条)、\(D\)(点)各有 \(m\) 个,\(W\)(白板)有一个,从中选取 \(n\) 个出来进行摆放。
麻将里面除了 \(W\) 外,有一张牌是 \(lucky\),摆放的时候这张牌要放在最前面。
摆放的两张牌都不是 \(lucky\) 的,那么 \(C\) 要在 \(B\) 前面,\(B\) 要在 \(D\) 前面。即 \(C 2\) 要在 \(B 1\) 前面。
若都是一样的类型,即都是 \(C\) 或者都是 \(B\) 或者都是 \(D\),则小的要在大的前面。即 \(C 2\) 要在 \(C 3\) 前面。
\(W\) 要放在 \(lucky\) 的牌原来在的位置。
求出有多少牌可能是 \(lucky\) 的。
例如题目的样例:
3 9
C 2
W
C 4
这个答案是 2,\(lucky\) 牌可以是 \(C 2\) 或者 \(C 3\)。将 \(C 2\) 放到开头后,将 \(W\) 放到它原来的位置,将 \(C 3\) 放到开头后,将 \(W\) 放到它原来的位置,显然都是成立的。
思路:
首先考虑没有 \(W\) 的时候,那么除了后面的 \(n - 1\) 张牌,所有的麻将都可能是 \(lucky\) 的。
若有 \(W\),且它在开头的时候,要分两种情况看,\(n == 1\) 的时候,所有牌都可能是 \(lucky\) 的,否则只有 \(C 1\) 到 第二张牌 - 1 这么多的牌可能是 \(lucky\) 的。
若 \(W\) 在结尾,那么就是最后一张牌 + 1 到 3 * \(m\) 的牌可能是 \(lucky\) 的。
在中间的话就是前面一张牌 + 1,到后面一张牌 - 1 的这些牌可能是 \(lucky\) 的。这时要考虑一种特殊情况,\(W\) 是第二张牌的时候,第一张牌也能够是 \(lucky\) 的。
接着还有一种情况,那就是开头和第二张不符合不是 \(lucky\) 的牌的顺序的时候,也就是第一张牌就是 \(lucky\) 的,所以它才不符合后面的顺序。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL T, n, m;
map < char, LL> dir;
char ch;
void solve(){
cin >> n >> m;
vector <LL> a(n + 2);
LL p = 0;
for (int i = 1; i <= n; ++ i){
cin >> ch;
if (ch != 'W'){
cin >> a[i];
a[i] += dir[ch] * m;
}
else p = i;
}
if (a[2] <= a[1] && n >= 2 && p != 2){
cout << "1\n";
return;
}
a[n + 1] = 3 * m + 1;
if (p == 0) cout << 3 * m - (n - 1) << "\n";
else if (p == 1 && n > 1) cout << a[2] - 1 << "\n";
else cout << a[p + 1] - a[p - 1] - (p != 2) << "\n";
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
dir['C'] = 0, dir['B'] = 1, dir['D'] = 2;
cin >> T;
while (T--)
solve();
return 0;
}
L - Doki Doki Literature Club
题目大意:
有 \(n\) 个单词,每个单词有一个喜爱值 \(f\),现在要选择 \(m\) 个单词写成一首诗,诗的总快乐值为 $\sum_{i = 1}^{m} (m - i + 1) * f(i) $,找到一种单词的排序方式,使诗的快乐值最大,若有多个方案,输出字典序最小的那一种。
思路:
因为 \(m - i + 1\) 是减少的,所以要让快乐值大的放在最前面,然后按照字典序升序一下就行。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int N = 110;
LL T, n, m;
struct node{
LL a;
string s;
}nd[N];
void solve(){
cin >> n >> m;
for (int i = 1; i <= n; ++ i)
cin >> nd[i].s >> nd[i].a;
sort( nd + 1, nd + n + 1, [](node a, node b){
if (a.a != b.a) return a.a > b.a;
return a.s < b.s;
});
LL ans = 0;
for (int i = 1; i <= m; ++ i)
ans += (m - i + 1) * nd[i].a;
cout << ans;
for (int i = 1; i <= m; ++ i)
cout << " " << nd[i].s;
cout << "\n";
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
cin >> T;
while (T--)
solve();
return 0;
}
M - Lucky 7
题目大意:
给一个长为 \(n\) 的序列,判断有没有一个元素加上 \(b\) 是 7 的倍数。
思路:
依次判断即可。
代码:
#include <bits/stdc++.h>
using namespace std;
#define LL long long
LL T, n, b;
void solve(){
cin >> n >> b;
vector <LL> a(n + 1);
for (int i = 1; i <= n; ++ i)
cin >> a[i];
for (int i = 1; i <= n; ++ i){
if ( (a[i] + b) % 7 == 0 ){
cout << "Yes\n";
return;
}
}
cout << "No\n";
}
int main(){
ios::sync_with_stdio(false);cin.tie(0);
cin >> T;
while (T--)
solve();
return 0;
}