猜结论专题

发布时间 2023-08-24 17:20:55作者: Sakana~

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. 1 的左边或右边有两个以上 0,则需 2 次;
  2. 0110 需要3次
  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 ();
}