L表示朝左,R表示朝右,想要每个棋子都能被至少一个别的棋子看到,所以必须出现LR,因为只能互换相邻的一次,当有RL时不需要互换,当有LR时要互换才能保证都能被看到
AC代码:
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
string s;
cin >> s;
bool ok = false;
for (int i = 0; i < n - 1; i++) {
if (s[i] == 'R' and s[i + 1] == 'L') {
cout << "0\n";
ok = true;
break;
} else if (s[i] == 'L' and s[i + 1] == 'R') {
cout << i + 1 << '\n';
ok = true;
break;
}
}
if (!ok) {
cout << "-1\n";
}
}
return 0;
}
MKnez's ConstructiveForces Task
构造s[i]使得s[i]不等于0并且相邻两个数等于所有数的和,偶数个很好构造,相邻是相反数即可,当n是奇数的时候,n=3无解,n>3构造总和为1或-1,相邻两数之和也为1或-1,发现1和-1的取值跟n/2的奇偶有关
AC代码:
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
if (n % 2 == 0) {
cout << "YES\n";
for (int i = 0; i < n; i++) {
if (i % 2 == 0) {
cout << "1 ";
} else {
cout << "-1 ";
}
}
cout << '\n';
} else {
if (n == 3) {
cout << "NO\n";
} else {
cout << "YES\n";
int p = n / 2;
int flag = (p & 1 ? -1 : 1);
for (int i = 0; i < n; i++) {
if (i % 2 == 1) {
cout << p * flag << " ";
} else {
cout << (-p + 1) * flag << " ";
}
}
cout << '\n';
}
}
}
return 0;
}
给定一个序列a,可以操作使得a[i]=-a[i]任意次,求所有前缀和都小于等于1到m的和,先考虑m前面的情况,化简一下式子可得sum[m]<=sum[i](i<=m),即sum[m]-sum[i]<=0,因为修改a[i]的取值,只会影响i及以后sum的取值,所以从m-1到1进行遍历,来表示sum[m]-sum[i]之间的和,即(i,m]的区间和,如果(i,m]区间和大于0是不符合的,所以用大根堆存下每个a[i],修改最大的a[i]的值,以及a[i]对sum的贡献,再看m+1到n,sum[m]<=sum[i](m<i<=n),即sum[i]-sum[m]>=0,意味着(m,i]的区间和要大于等于0,所以用小根堆存所有数m+1到n,贪心地修改最小的负数
AC代码:
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n >> m;
int ans = 0;
vector<LL> a(n + 1);
priority_queue<pair<LL, int>, vector<pair<LL, int>>, less<pair<LL, int>>> q;
priority_queue<pair<LL, int>, vector<pair<LL, int>>, greater<pair<LL, int>>> q1;
for (int i = 1; i <= n; i++) {
cin >> a[i];
}
q.push(make_pair(a[m], m));
LL sum = a[m];
for (int i = m - 1; i >= 1; i--) {
while (sum > 0) {
ans++;
sum -= q.top().first * 2;
q.push(make_pair(-q.top().first, q.top().second));
a[q.top().second] = -a[q.top().second];
q.pop();
}
sum += a[i];
q.push(make_pair(a[i], i));
}
sum = 0;
for (int i = m + 1; i <= n; i++) {
sum += a[i];
q1.push(make_pair(a[i], i));
while (sum < 0) {
ans++;
sum -= 2 * q1.top().first;
a[q1.top().second] = -a[q1.top().second];
q1.push(make_pair(-q1.top().first, q1.top().second));
q1.pop();
}
}
cout << ans << '\n';
}
return 0;
}
容易知道a[i]如果小于b[i]一定不可能,在一段区间内,区间最大值可以尽可能大的跨范围减,因为不会影响比他小的数,如果使用区间最大值一定不会影响其他的数,考虑单调栈求解,分两种情况a[i]==b[i]和a[i]!=b[i],当a[i]==b[i]时,要把比b[i]小的全部退出去,因为他们已经用过次数,不影响后面使用,当a[i]!=b[i]时,重复上述操作,如果栈空了或者栈顶不是b[i],说明b[i]比栈顶小,使用一次并放入栈中,判断推子的次数有没有小于0的即可
AC代码:
#include <bits/stdc++.h>
using namespace std;
using LL = long long;
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T;
cin >> T;
while (T--) {
int n, m;
cin >> n;
vector<int> a(n), b(n);
bool ok = true;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
for (int i = 0; i < n; i++) {
cin >> b[i];
if (a[i] < b[i]) {
ok = false;
}
}
cin >> m;
map<int, int> mp;
for (int i = 0; i < m; i++) {
int x;
cin >> x;
mp[x]++;
}
if (!ok) {
cout << "NO\n";
continue;
}
stack<int> st;
for (int i = 0; i < n; i++) {
if (a[i] == b[i]) {
while (!st.empty() and st.top() < b[i]) {
st.pop();
}
} else {
while (!st.empty() and st.top() < b[i]) {
st.pop();
}
if (st.empty() or st.top() != b[i]) {
mp[b[i]]--;
st.push(b[i]);
if (mp[b[i]] < 0) {
ok = false;
break;
}
}
}
}
if (ok) {
cout << "YES\n";
} else {
cout << "NO\n";
}
}
return 0;
}