https://codeforces.com/contest/1976
利ASCII码表特点,字母的二进制值比数字大。
#include <bits/stdc++.h>
using namespace std;
int n;
string s;
void solve() {
cin >> n >> s;
for (int i = 1; i < s.size(); i++) {
if (s[i] < s[i - 1]) {
cout << "NO" << endl;
return;
}
}
cout << "YES" << endl;
}
int main() {
int tt;
cin >> tt;
while (tt--) {
solve();
}
return 0;
}
对于前n
位,修改abs(a[i] - b[i])
次使a[i]
变成b[i]
是必须的。
对于第n+1
位,如果在之前的修改过程中出现过,那么可以直接移过来,操作次数为1
。
如果之前没出现过,那么就找一个离b[n+1]
最近的。
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int N = 2e5 + 5;
int n;
int a[N], b[N];
void solve() {
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n + 1; i++)
cin >> b[i];
ll ans = 0;
int mn = 1e9;
for (int i = 1; i <= n; i++) {
ans += abs(a[i] - b[i]);
if (min(a[i], b[i]) <= b[n + 1] && b[n + 1] <= max(a[i], b[i]))
mn = 0;
mn = min({mn, abs(a[i] - b[n + 1]), abs(b[i] - b[n + 1])});
}
cout << ans + mn + 1 << endl;
}
int main() {
int tt;
cin >> tt;
while (tt--) {
solve();
}
return 0;
}
一定有:开发多了,或,测试多了。
n+1
才有可能选到开发,剩下的所有人都是测试m+1
才有可能选到测试,剩下的所有人都是开发如果开发多了:
i
个缺席者在其中,那么第n+1
个开发会从测试转为开发
b. 如果第i
个缺席者不在其中,无论原先是开发还是测试,他都只能测试#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define ll long long
const int N = 2e5 + 5;
int n, m;
int a[N], b[N];
int good[N];
void solve() {
cin >> n >> m;
ll sa = 0, sb = 0;
for (int i = 1; i <= n + m + 1; i++)
cin >> a[i], sa += a[i];
for (int i = 1; i <= n + m + 1; i++)
cin >> b[i], sb += b[i];
vector<int> pos[2];
for (int i = 1; i <= n + m + 1; i++) {
pos[a[i] < b[i]].push_back(i);
good[i] = 0;
}
ll sa1 = 0, sb1 = 0;
if (pos[0].size() > n) {
for (int i = 0; i < n; i++) {
sa1 += a[pos[0][i]];
sb1 += b[pos[0][i]];
good[pos[0][i]] = 1;
}
for (int i = 1; i <= n + m + 1; i++) {
if (!good[i]) {
cout << sa1 + sb - sb1 - b[i] << ' ';
} else {
cout << sa1 - a[i] + a[pos[0][n]] + sb - sb1 - b[pos[0][n]]
<< ' ';
}
}
} else {
for (int i = 0; i < m; i++) {
sa1 += a[pos[1][i]];
sb1 += b[pos[1][i]];
good[pos[1][i]] = 1;
}
for (int i = 1; i <= n + m + 1; i++) {
if (!good[i]) {
cout << sb1 + sa - sa1 - a[i] << ' ';
} else {
cout << sb1 - b[i] + b[pos[1][m]] + sa - sa1 - a[pos[1][m]]
<< ' ';
}
}
}
cout << endl;
}
int main() {
IOS;
int tt;
cin >> tt;
while (tt--) {
solve();
}
return 0;
}
扫描线。
把左括号赋值为1
,右括号赋值为-1
。
前缀和会表现为一个折线图。
如果选择翻转某个区间的左右括号,相当于把折线图向下对折。
向下对折之后,任一点不应小于0
。
i*2
,i
为两端点高度。组合计数采用的是:枚举右端点,统计所有合法左端点。
#include <bits/stdc++.h>
using namespace std;
#define IOS ios::sync_with_stdio(0), cin.tie(0), cout.tie(0)
#define ll long long
const int N = 2e5 + 5;
int n, m;
string s;
int a[N], pre[N];
vector<int> h[N];
struct Node {
int mx;
} T[N << 2];
Node merge(Node &l, Node &r) { return {max(l.mx, r.mx)}; }
void build(int p, int l, int r) {
if (l == r) {
T[p].mx = pre[l];
} else {
int mid = l + r >> 1;
if (l <= mid)
build(p << 1, l, mid);
if (mid < r)
build(p << 1 | 1, mid + 1, r);
T[p] = merge(T[p << 1], T[p << 1 | 1]);
}
}
int query(int p, int l, int r, int nl, int nr) {
if (nl <= l && r <= nr)
return T[p].mx;
int mid = l + r >> 1;
int ans = 0;
if (nl <= mid)
ans = max(ans, query(p << 1, l, mid, nl, nr));
if (mid < nr)
ans = max(ans, query(p << 1 | 1, mid + 1, r, nl, nr));
return ans;
}
void solve() {
cin >> s;
n = s.size();
for (int i = 0; i <= n; i++)
h[i].clear();
for (int i = 1; i <= n; i++) {
a[i] = s[i - 1] == '(' ? 1 : -1;
pre[i] = pre[i - 1] + a[i];
h[pre[i]].push_back(i);
}
ll res = 0;
build(1, 1, n);
for (int i = 0; i <= n; i++) {
int lst = -1;
for (int j = 0; j + 1 < h[i].size(); j++) {
int mh = query(1, 1, n, h[i][j], h[i][j + 1]);
if (mh > i * 2)
lst = j;
res += j - lst;
}
}
cout << res << endl;
}
int main() {
IOS;
int tt;
cin >> tt;
while (tt--) {
solve();
}
return 0;
}