猜结论专题
A - Non-Adjacent Flip
https://atcoder.jp/contests/arc156/tasks/arc156_a
题意
给定一个01串,每次可以把不相邻的两个字符进行翻转,问最少要操作多少次使得全部变为0,无解输出-1。
分析
记录 \(1\) 的数量为 \(cnt\)。
每次翻转不改变 \(1\) 的奇偶性,所以 \(1\) 的数量为奇数时无解。
\(cnt>2\) 时,答案均为 \(\frac{cnt}2\)(每次可以翻转不相邻的 \(1\))
\(cnt=2\) 时,若两个 \(1\) 不相邻,则需 \(1\) 次,否则分为以下三种情况:
- 1 的左边或右边有两个以上 0,则需 2 次;
0110
需要3次- 其余情况如
011
110
11
均无解
Code
#include <bits/stdc++.h>
using namespace std;
void solve () {
int n;
string s;
cin >> n >> s;
int tt = count (s.begin (), s.end (), '1');
if (tt & 1) tt = -1;
else if (tt == 2) {
int l = -1, r = -1;
for (int i = 0; i < s.size (); i++) {
if (s[i] == '1') {
if (l == -1) l = i;
else r = i;
}
}
if (r - l > 1) tt = 1;
//1100 -> 2
else if (l > 1 || r < n - 2) tt = 2;
//0110 -> 3
else if (s == "0110") tt = 3;
else tt = -1;
}
else tt /= 2;
cout << tt << endl;
}
int main () {
int t;
cin >> t;
while (t--) solve ();
}
A. Almost Increasing Subsequence
https://codeforces.com/contest/1817/problem/A
题意
给一个序列,对于一个子区间,回答最长几乎上升子序列长度
也就是不能有连续三项 \(x\geq y\geq x\)
分析
划分成若干下降序列,每次可选的点是下降序列的左右端点。
做前缀和查询。
对于每次的查询的右端点,若原本不可选,则再给答案加上贡献。
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 5;
int n, q, a[N], b[N], sum[N];
int main () {
cin >> n >> q;
for (int i = 1; i <= n; i++) cin >> a[i];
int lst = 1;
for (int i = 1; i <= n; i++) {
if (a[i] > a[i-1]) b[lst] = b[i-1] = 1, lst = i;
}
b[lst] = b[n] = 1;
//for (int i = 1; i <= n; i++) cout << b[i] << ' ';
//cout << endl;
for (int i = 1; i <= n; i++) sum[i] = sum[i-1] + b[i];
while (q--) {
int l, r;
cin >> l >> r;
int cnt = sum[r] - sum[l-1];
if (!b[l]) cnt++;
if (l != r && !b[r]) cnt++;
cout << cnt << endl;
}
}
//x>=y>=z 的 y 就不选
//分成若干降序列
C. Between
https://codeforces.com/contest/1815/problem/C
题意
构造一个序列,每个元素1到n之间
- 恰好一个1。
- 若干个限制,两个ai之间,至少一个bi,问最长的序列。
分析
差分约束
Code
#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> pii;
const int N = 5005, M = 5005, inf = 0x3f3f3f3f;
int n, m, h[N], e[M], ne[M], idx;
int dis[N];
bool vis[N];
pii p[N];
void add (int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
void bfs (int st) {
queue <int> q;
q.push (st);
dis[st] = 1;
while (!q.empty ()) {
auto t = q.front ();
q.pop ();
if (vis[t]) continue;
vis[t] = true;
for (int i = h[t]; ~i; i = ne[i]) {
int j = e[i];
if (dis[j] > dis[t] + 1) {
dis[j] = dis[t] + 1;
q.push (j);
}
}
}
}
void solve () {
idx = 0;
scanf ("%d%d", &n, &m);
for (int i = 1; i <= n; i++) {
h[i] = -1, dis[i] = inf;
vis[i] = false;
}
while (m--) {
int a, b;
scanf ("%d%d", &a, &b);
add (b, a);
}
bfs (1);
int cnt = 0, maxn = 0;
for (int i = 1; i <= n; i++) {
if (dis[i] == inf) {
printf ("INFINITE\n");
return ;
}
//cout << dis[i] << ' ';
cnt += dis[i], maxn = max (maxn, dis[i]);
p[i] = {dis[i], i};
}
printf ("FINITE\n%d\n", cnt);
sort (p + 1, p + n + 1, greater<pii>());
for (int i = 1, j = n; i <= maxn; i++) { //次数<=i的都能输出
while (p[j].first < i) j--;
for (int k = 1; k <= j; k++) printf ("%d ", p[k].second);
}
printf ("\n");
}
int main () {
int t;
scanf ("%d", &t);
while (t--) solve ();
}
G. The Game of the Century
https://codeforces.com/contest/1779/problem/G
题意
最少改多少条边使得整个图强连通
分析
如果都往一个方向就改,最多n条边
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
map<char, vector<int>> v;
void solve () {
int n, ans = 0;
cin >> n;
v.clear ();
for (int i = 0; i < 3; i++) {
string s;
cin >> s;
int cnt = 0;
for (int j = n - 1; j >= 0; j--) {
if (s[j] == s.back ()) cnt++; //往同一方向走
else break; //折返
}
v[s.back ()].push_back (cnt);
}
for (auto i : v['0']) {
for (auto j : v['1']) {
ans += min (i, j); //修改小的
}
}
ans = min (ans, n); //有交叉直接改n条边
cout << ans << endl;
}
int main () {
int t;
cin >> t;
while (t--) solve ();
}
B - Insertion Sort 2
https://atcoder.jp/contests/arc162/tasks/arc162_b
题意
给一个排列,每次删除相邻两项,插入到其他地方去,不超过 2n 次操作变成有序。
分析
排列奇偶性,鸡排列无解,偶排列有解。
Code
809. 【UNR #7】那些你不要的
题意
给2n+1个数,Alice和Bob轮流删除其中相邻两项,一个要剩下的最大,一个要最小。最后剩多少。
分析
注意每次删除的时候每个数位置的奇偶性不变,最后剩下来的是下表为奇数的数。
所以只需要考虑下标为奇数的数,A从小的开始删,B从大的开始删
Code
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 5;
void solve () {
int n, x;
vector<int> v;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> x;
if (i & 1) v.push_back (x);
}
sort (v.begin (), v.end ());
//for (auto i : v) cout << i << ' ';
cout << v[(n + 1) / 4] << endl;
}
int main () {
int t;
cin >> t;
while (t--) solve ();
}
C - Permutation Addition
https://atcoder.jp/contests/arc159/tasks/arc159_c