A. Consecutive Sum
题目链接 :
题面 :
题目大意:
给一个由n个整数组成的数组a,可以进行k次以下操作:
1.选择两个下标i和j,满足i mod k = j mod k
2.交换ai和aj
操作结束后选择k个连续的数,相加的值为获得的分数,找到你可以获得的最大分数。
思路:
总体思路:将要找的数全部放在前k个位置,则计算分数时只需相加前k个数的值。
操作:对于1 <= i <= k,循环相加k,判断a[i] 和 a[i + cnt * k]的大小(cnt的值为循环相加k的次数)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e6 + 10;
const ll mod = 1e11 + 3;
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
ll a[1000], b[1000];
void solve() {
int n, k;
cin >> n >> k;
for (int i = 1 ; i <= n; i++) {
cin >> a[i];
}
for (int i = 1; i <= k; i++) {
int cnt = 1;
b[i] = a[i];
while (i + cnt * k <= n) {
if (b[i] < a[i + cnt * k]) b[i] = a[i + cnt * k];
cnt++;
}
}
ll ans = 0;
for (int i = 1; i <= k; i++) {
ans += b[i];
}
cout << ans << "\n";
}
int main() {
IOS;
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
B. Rule of League
题目链接:
题面:
题目大意:
有n个选手参加比赛。
首先,一号选手和二号选手比赛,胜者与三号选手比赛,胜者与四号选手比赛…
对于每个选手,他要么赢了x场比赛,要么赢了y场比赛。
问是否存在一种情况使得上述条件成立。
思路:
对于x和y,显然当x=0并且y=0时,找不到任何一种情况满足条件。
同理,当x≠0并且y≠0时,找不到任何一种情况满足条件,因为一号选手和二号选手必定有一位只能参加一场比赛,所以必有一位赢0场。
综上所述,x和y中必存在一个0。
当(n - 1)%(x + y) ≠0时,也不满足条件。
对于能够满足条件的情况,只需令(n - 1)/(x + y)名选手各赢(x + y)场即可。
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e6 + 10;
const ll mod = 1e11 + 3;
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
void solve() {
int n, x, y;
cin >> n >> x >> y;
if ((x != 0 && y != 0) || (x == 0 && y == 0)) {
cout << -1 << "\n";
return ;
}
if (x == 0) {
if ((n - 1) % y == 0) {
int m = (n - 1) / y;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= y; j++) cout << 1 + (i - 1) * y + 1 << ' ';
}
cout << "\n";
}else cout << -1 << "\n";
}else if (y == 0){
if ((n - 1) % x == 0) {
int m = (n - 1) / x;
for (int i = 1; i <= m; i++) {
for (int j = 1; j <= x; j++) cout << 1 + (i - 1) * x + 1 << ' ';
}
cout << "\n";
} else cout << -1 << "\n";
}
}
int main() {
IOS;
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
C.Parity Shuffle Sorting
题目链接:
Problem - C - Parity Shuffle Sorting
题面:
题目大意:
有一个由n个非负整数组成的数组a,进行以下操作:
1.选择下标l和r
2.当al + ar的值为奇数时,令ar = al,若为偶数,令al = ar
要求使用不超过n次操作,使数组有序且非递减
思路:
令数组内所有数的值都变为a[n]
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5 + 10;
const ll mod = 1e11 + 3;
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
int a[MAX];
int check(int a, int b) {
return (a + b) % 2;
}
void solve() {
int n;
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
if (is_sorted(a + 1, a + 1 + n) || n == 1) {
cout << 0 << "\n";
return ;
}
vector<pair<int, int>> vc;
if (check(a[1], a[n])) {
a[n] = a[1];
vc.push_back({1, n});
}
for (int i = 1; i < n; i++) {
if (!check(a[i], a[n]) && a[i] != a[n]) {
a[i] = a[n];
vc.push_back({i, n});
}
}
for (int i = 2; i < n; i++) {
if (check(a[1], a[i])) {
a[i] = a[1];
vc.push_back({1, i});
}
}
cout << vc.size() << "\n";
for (int i = 0; i < vc.size(); i++) {
cout << vc[i].first << " " << vc[i].second << "\n";
}
}
int main() {
IOS;
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
D1. Zero-One (Easy Version)
题目链接:
Problem - D1 - Zero-One (Easy Version)
题面:
题目大意:
给两个01串a, b,对01串a进行如下操作使得a=b
1.选择下标l和r
2.将al的值改为1-al,将ar的值改为1-ar
如果l+1=r,代价为x,反之,代价为y
求最小花费和操作步骤
思路:
记录两个01串不同的位置。
因为每次操作有两个位置的值改变,所以当位置数%2≠0时,不存在操作满足条件。
因为题目限制了x>=y,所以优先变换两个位置差大于1的。
当位置数>2时,全部选择y花费来操作。
当位置数=2时,花费为min(x,2 *y)
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 1e5 + 10;
const ll mod = 1e11 + 3;
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
int pos[3005];
void solve() {
int n;
ll x, y;
cin >> n >> x >> y;
string s1, s2;
cin >> s1 >> s2;
int cnt = 0;
for (int i = 0; i < n; i++) {
if (s1[i] != s2[i]) pos[++cnt] = i;
}
if (cnt % 2 != 0) {
cout << -1 << "\n";
return ;
}
if (cnt == 0) {
cout << 0 << "\n";
return ;
}
if (cnt == 2 && pos[2] - pos[1] == 1) cout << min(x, y * 2) << "\n";
else {
cout << y * cnt / 2 << "\n";
}
}
int main() {
IOS;
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}
D2.Zero-One (Hard Version)
题目链接:
Problem - D2 - Zero-One (Hard Version)
题面:
题目大意:
与D1大致一样,少了x >= y的限制和数组范围的扩大
思路:
动态规划:
设dp[i][j]表示将a[i,j]变为b[i,j]所需的最小花费
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int MAX = 2e5 + 10;
const ll mod = 1e11 + 3;
#define IOS std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
int n;
string s1, s2;
ll x, y;
ll dp[5005][5005];
vector<int> vc;
int calc(int i, int j) {
int pos = vc[j] - vc[i];
if (pos == 1) return min(x, y * 2);
else return min(x * pos, y);
}
void solve() {
cin >> n >> x >> y;
cin >> s1 >> s2;
vc.clear();
for (int i = 0; i < n; i++) {
if (s1[i] != s2[i]) {
vc.push_back(i);
}
}
int l = vc.size();
if (l % 2 == 1) {
cout << -1 << "\n";
return ;
}
for (int k = 2; k <= l; k += 2 ) {
for (int i = 0; i + k - 1 < l; i ++ ) {
int j = i + k - 1;
if (k == 2) dp[i][j] = calc(i, j);
else
dp[i][j] = min({dp[i][j - 2] + calc(j - 1, j), dp[i + 1][j - 1] + calc(i, j), dp[i + 2][j] + calc(i, i + 1), y * (j - i + 1) / 2});
}
}
cout << dp[0][l - 1] << "\n";
}
int main() {
IOS;
int t;
cin >> t;
while (t--) {
solve();
}
return 0;
}