Explanation of the third session of 2022 Niuke winter camp

Posted by andrewmcgibbon on Fri, 04 Feb 2022 15:23:44 +0100

Question A Zhinai's Hello XXXX (sign in)

Output \ (\ text{hello xxx} \), where xxx can be any string

Just output whatever you want to sign in, but it's still recommended to follow a string composed of ASCII code to prevent random code.

print("hello world")

Question B Wisdom is buying melons (01 backpack)

Now there are \ (n \) melons, and the quality of \ (I \) melon is \ (w_i \).

Now, for each melon, we can choose:

  1. Buy this melon
  2. Split the melon in half and buy only half
  3. Don't buy

Now we want to know, when the quality sum of melons we buy is \ (1,2,\cdots,M \), how many schemes are there respectively?

\(0\leq n\leq 10^3,1\leq M \leq10^3,2\leq w_i\leq 2*10^3 \), ensure that \ (w_i \) is even

If you don't split melons, it's a typical 01 knapsack statistical scheme. If you split melons, it's almost the same.

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9 + 7;
const int N = 1010;
int n, m, w[N];
int dp[N][N];
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; ++i)
        cin >> w[i];
    dp[0][0] = 1;
    for (int i = 1; i <= n; ++i)
        for (int j = 0; j <= m; ++j) {
            dp[i][j] = dp[i - 1][j];
            if (j >= w[i])
                dp[i][j] = (dp[i][j] + dp[i - 1][j - w[i]]) % mod;
            if (j >= w[i] / 2)
                dp[i][j] = (dp[i][j] + dp[i - 1][j - w[i] / 2]) % mod;
        }
    for (int i = 1; i <= m; ++i)
        printf("%d ", dp[n][i]);
    return 0;
}

Question C Another version (reverse DP)

This question has the same background as the above, but this question is given the purchase quality and the number of schemes when it is \ (1,2,\cdots,M \) (modulo \ (10 ^ 9 + 7 \). Let's construct the quality of these melons in turn.

\(1\leq M \leq 10^3\)

For a given number of schemes, we can obviously find the \ (w \) of an item: if the number of schemes with mass and \ (x \) is greater than 0, and the number of schemes with mass and less than \ (x \) is 0, then there must be a melon with mass \ (2x \), which we store in the answer number group.

We know that the DP equation of question B is:

\[dp_{i,j}=dp_{i-1,j}+dp_{i-1,j-w_i}+dp_{i-1,j-\frac{w_i}{2}} \]

Then shift and transform, get

\[dp_{i-1,j}=dp_{i,j}-dp_{i-1,j-w_i}-dp_{i-1,j-\frac{w_i}{2}}\\ dp_{i,j}=dp_{i + 1,j}-dp_{i,j-w_{i+1}}-dp_{i,j-\frac{w_{i+1}}{2}} \]

In this way, we get the inverse DP equation of the original DP equation, which can be deduced.

When the whole DP array becomes all 0, end the process and output the number recorded in the answer array.

#include<bits/stdc++.h>
using namespace std;
const int M = 1010;
const int mod = 1e9 + 7;
int m, dp[2][M];
vector<int> ans;
int main()
{
    dp[0][0] = dp[1][0] = 1;
    cin >> m;
    for (int i = 1; i <= m; ++i) cin >> dp[0][i];
    for (int i = 1; ;++i) {
        int w = -1;
        for (int j = 1; j <= m && w == -1; ++j)
            if (dp[(i - 1) % 2][j]) w = 2 * j;
        if (w == -1) break;
        ans.push_back(w);
        for (int j = 1; j <= m; ++j) {
            dp[i % 2][j] = dp[(i - 1) % 2][j];
            if (j >= w / 2) {
                dp[i % 2][j] -= dp[i % 2][j - w / 2];
                //If it becomes negative when subtracting, add mod. The same is true below
                if (dp[i % 2][j] < 0) dp[i % 2][j] += mod;
            }
            if (j >= w) {
                dp[i % 2][j] -= dp[i % 2][j - w];
                if (dp[i % 2][j] < 0) dp[i % 2][j] += mod;
            }
        }
    }
    cout << ans.size() << endl;
    for (int w : ans) cout << w << ' ';
    return 0;
}

Question D Zhinai's 01 string disrupts (sign in)

Disrupt a pure 01 string to ensure that the string is not all 0 or all 1.

Find a 1 and a 0 position and exchange it.

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n;
char s[N];
int main()
{
    scanf("%d%s", &n, s + 1);
    for (int i = 1; i < n; ++i)
        if (s[i] != s[i + 1]) {
            swap(s[i], s[i + 1]);
            break;
        }
    puts(s + 1);
    return 0;
}

Question E Zhinai's digital building block (easy version) (sort, simulate)

There are now \ (n \) blocks, each with a one digit number and a color. The position of two adjacent building blocks with the same color can be changed.

Now that we have paint, we can paint all the blocks in the color of \ (p_i \) as \ (p_i \) at the \ (I \) time.

Q: after \ (k \) times of painting, what is the maximum value (ten digits read from left to right, leading 0 allowed) that the building blocks can be arranged each time? (including initial condition and after each painting)

\(1\leq n,m\leq 10^5,0\leq k\leq 10\)

Suddenly found that each building block will only be in its own color block, so find it directly and then hard sort it.

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
#define LL long long
const LL mod = 1e9 + 7;
int n, m, k;
struct Node {
    int color, num;
    bool operator < (const Node &rhs) const {
        return num > rhs.num;
    }
} a[N];
//
void change(int p, int q) {
    for (int i = 1; i <= n; ++i)
        if (a[i].color == p) a[i].color = q;
}
Node t[N];
LL solve() {
    for (int i = 1; i <= n; ++i) t[i] = a[i];
    //
    int L = 1;
    while (L <= n) {
        int R = L;
        while (R <= n && t[R].color == t[L].color) R++;
        sort(t + L, t + R);
        L = R;
    }
    LL res = 0;
    for (int i = 1; i <= n; ++i)
        res = (res * 10 + t[i].num) % mod;
    return res;
}
char s[N];
int main()
{
    //read
    scanf("%d%d%d", &n, &m, &k);
    scanf("%s", s + 1);
    for (int i = 1; i <= n; ++i)
        a[i].num = s[i] - '0';
    for (int i = 1; i <= n; ++i)
        scanf("%d", &a[i].color);
    //solve
    cout << solve() << endl;
    for (int i = 1; i <= k; ++i) {
        int p, q;
        scanf("%d%d", &p, &q);
        change(p, q);
        cout << solve() << endl;
    }
    return 0;
}

Question G Easy version of zhinai's tree (Analog)

Given two binary trees with \ (n \) nodes, can the previous binary tree be transformed into the latter by multiple rotations?

\(n\leq 10^3 \), ensure that the answer does not exceed 1

Ensure that the answer is no more than 1, and the scale of \ (n \) is not large, which is equivalent to simulating rotation (the knowledge of balance tree is completely forgotten, which belongs to yes)

#include<bits/stdc++.h>
using namespace std;
const int N = 1010;
int n;
struct Node {
    int l, r;
} a[N], b[N], t[N];
int fa[N];
int check(int x) {
    return a[fa[x]].r == x;
}
void zag(int &B) {
    int A = fa[B], beta = t[B].l;
    t[A].r = beta, t[B].l = A;
    int X = fa[A];
    if (X) {
        if (t[X].l == A) t[X].l = B;
        else t[X].r = B;
    }
}
void zig(int &A) {
    int B = fa[A], beta = t[A].r;
    t[B].l = beta, t[A].r = B;
    int X = fa[B];
    if (X) {
        if (t[X].l == B) t[X].l = A;
        else t[X].r = A;
    }
}
void rorate(int x) {
    for (int i = 1; i <= n; ++i) t[i] = a[i];
    check(x) ? zag(x) : zig(x);
}
bool isAns() {
    int flag = true;
    for (int i = 1; i <= n && flag; ++i)
        if (t[i].l != b[i].l || t[i].r != b[i].r)
            flag = false;
    return flag;
}
int main()
{
    //read
    cin >> n;
    for (int i = 1; i <= n; ++i)
        cin >> b[i].l >> b[i].r;
    for (int i = 1; i <= n; ++i)
        cin >> a[i].l >> a[i].r;
    //solve
    //k=0
    for (int i = 1; i <= n; ++i)
        t[i] = a[i];
    if (isAns()) {
        puts("0");
        return 0;
    }
    //k=1
    for (int i = 1; i <= n; ++i) {
        int l = a[i].l, r = a[i].r;
        if (l) fa[l] = i;
        if (r) fa[r] = i;
    }
    for (int i = 1; i <= n; ++i)
        if (fa[i]) {
            rorate(i);
            if (isAns()) {
                printf("1\n%d", i);
                return 0;
            }
        }
    return 0;
}

Of course, there is another way without rotation: if two nodes \ (i,j \) are parents and children of each other in two trees, they must be rotated. At this time, the node that was originally the father is output.

Question I Zhinai's password (double pointer)

Given a string of length \ (n \), it consists entirely of uppercase letters, lowercase letters, numbers and special characters. Now, we want to choose a substring as the password, and the requirements are:

  1. The password length is within \ ([L,R] \)
  2. The password contains at least three or more characters

\(1\leq n\leq 10^5,1\leq L\leq R\leq n\)

The double pointer with restrictions is very simple, but it's a little troublesome to adjust.

#include<bits/stdc++.h>
using namespace std;
const int N = 100010;
int n, L, R;
char s[N];
//
int check(int c) {
    if (c >= 'A' && c <= 'Z') return 1;
    if (c >= 'a' && c <= 'z') return 2;
    if (c >= '0' && c <= '9') return 3;
    return 4;
}
int type[N];
int main()
{
    scanf("%d%d%d%s", &n, &L, &R, s + 1);
    for (int i = 1; i <= n; ++i)
        type[i] = check(s[i]);
    long long ans = 0;
    int vis[5] = {0, 0, 0, 0, 0};
    int l = 1, r = 0, cnt_type = 0;
    while (l <= n) {
        while (r < n && cnt_type < 3) {
            r++;
            vis[type[r]]++;
            if (vis[type[r]] == 1) cnt_type++;
        }
        //
        if (r == n && cnt_type < 3) break;
        while (l < r && cnt_type >= 3) {
            ans += max(min(n, l + R - 1) - max(r, l + L - 1) + 1, 0);

            vis[type[l]]--;
            if (vis[type[l]] == 0) cnt_type--;
            l++;
        }
    }
    cout << ans;
    return 0;
}

L question Zhinai's database (simulation, map)

See the title for details

We first use various means to separate the required strings in the instruction (substr and then split, which is really annoying), and then directly simulate it (all the simulation of strings, all map s, eternal God)

#include <bits/stdc++.h>
using namespace std;
const int N = 1010;
int n, m;
string title[N];
map<string, int> vis;
int Data[N][N];
vector<string> split_cmd()
{
    string cmd;
    getline(cin, cmd);
    getline(cin, cmd);
    string str = cmd.substr(36, cmd.length() - 37);

    vector<string> res;
    if (str == "") return res;
    string delim = ",";
    char *strs = new char[str.length() + 1];
    strcpy(strs, str.c_str());
    char *d = new char[delim.length() + 1];
    strcpy(d, delim.c_str());

    char *p = strtok(strs, d);
    while (p) {
        string s = p;
        res.push_back(s);
        p = strtok(NULL, d);
    }
    return res;
}
string build(int id, vector<string> &strs) {
    string res = "";
    for (string str : strs) {
        int dat = Data[id][vis[str]];
        if (res != "") res += ",";
        res += to_string(dat);
    }
    return res;
}
int main()
{
    cin >> n >> m;
    for (int i = 1; i <= m; ++i)
        cin >> title[i];
    for (int i = 1; i <= n; ++i) vis[title[i]] = i;
    for (int i = 1; i <= n; ++i)
        for (int j = 1; j <= m; ++j)
            cin >> Data[i][j];
    //
    vector<string> id = split_cmd();
    map<string, int> ans;
    for (int i = 1; i <= n; ++i)
        ans[build(i, id)]++;
    //output
    cout << ans.size() << endl;
    for (auto x : ans)
        cout << x.second << " ";
    return 0;
}

Topics: acm