1968(div3)

A. Maximize?

给你一个整数 x 。您的任务是找出任意一个整数 y ,使得 gcd(x,y)+y 为最大可能数。 (1y<x) 使得 gcd(x,y)+y 最大。

直接模拟即可。

void solve() {
    int n;cin >> n;
    int ans = -1, ret = -1;
    for (int i = 1;i < n;i++) {
        int x = __gcd(n, i) + i;
        if (x > ans) {
            ans = x;
            ret = i;
        }
    }
    cout << ret << '\n';
}

B. Prefiquence

给您两个二进制字符串 ab

您的任务是确定最大可能的数字 k ,使得长度为 k 的字符串 a 的前缀是字符串 b 的子序列。

双指针

void solve() {
    int n, m;cin >> n >> m;string a, b;cin >> a >> b;
    int j = 0, cnt = 0;
    for (int i = 0;i < m;i++) {
        if (b[i] == a[j]) {
            cnt++;j++;
        }
    }
    cout << cnt << '\n';
}

C. Assembly via Remainders

给你一个数组 x2,x3,,xn 。你的任务是找出任意一个数组 a1,,an ,其中:

构造

void solve() {
    int n;cin >> n;vector<int> x(n + 1), a(n + 1);
    for (int i = 2;i <= n;i++)cin >> x[i];
    a[1] = x[2] + 1;
    for (int i = 2;i <= n;i++) {
        a[i] = x[i];
        while (i != n && a[i] <= x[i + 1]) {
            a[i] += a[i - 1];
        }
    }
    for (int i = 1;i <= n;i++)cout << a[i] << " \n"[i == n];
}

D. Permutation Game

Bodya 和 Sasha 发现了一个排列 p1,,pn 和一个数组 a1,,an 。他们决定玩一个著名的 "排列游戏"。

它们都选择了排列的起始位置。

对局持续了 k 个回合。棋手同时下棋。在每个回合中,每个棋手都会发生两件事:

在整整 k 个回合后,得分较高的一方即为获胜者。

知道了博迪娅的起始位置 PB 和萨沙的起始位置 PS 后,如果双方都想获胜,那么谁会赢得对局?

Solution

分别单独计算 B,S 得分最大值。计算最终落在能到达的每个位置的值,能够证明走过的点只走一次,最终的点走很多次

#define int long long
void solve() {
    int n, k, b, s;cin >> n >> k >> b >> s;vector<int> p(n + 1), a(n + 1);
    for (int i = 1;i <= n;i++)cin >> p[i];
    for (int i = 1;i <= n;i++)cin >> a[i];

    auto cal = [&](int x) {
        int r = 0, cur = 0;
        for (int i = 0;i < k && i <= n + 1;i++) {
            r = max(r, cur + (k - i) * a[x]);
            cur += a[x];
            x = p[x];
        }
        return r;
        };

    int x = cal(b);
    int y = cal(s);
    if (x == y) {
        cout << "Draw\n";
    } else if (x > y) {
        cout << "Bodya\n";
    } else {
        cout << "Sasha\n";
    }
}

E. Cells Arrangement

给你一个整数 n 。您在网格 n×n 中选择 n 单元格 (x1,y1),(x2,y2),,(xn,yn)1xi,yin

假设 H 是任意一对单元格之间不同的曼哈顿距离集合。你的任务是最大化 H 的大小。

Solution

构造

n4 时,H 就是 [0,2n2] 的集合。

void solve() {
    int n;cin >> n;
    if (n == 2) {
        cout << "1 1\n1 2\n";return;
    }
    if (n == 3) {
        cout << "2 1\n2 3\n 3 1\n";return;
    }
    cout << "1 1\n1 2\n4 2\n4 4\n";
    for (int i = 5;i <= n;i++)cout << i << ' ' << i << '\n';
}

这里当 n=4 时,H1=0,1,2,3,4,5,6=[0,6],刚好满足条件
n5 时,n 每递增一次,H 最大值只会增加 2

每次在对角线上添加一个时,每个数字都可以增加 2,即 H2=(H1+2)+H1=[0,2n2]

F. Equal XOR Segments

如果可以将一个数组分成个数组,我们就称它为 x1,,xm 个有趣的数组。

k>1 个部分,使得每个部分的值的 bitwise XOR 都相等,那么这个数组就是有趣的数组。

更正式地说,你必须把数组 x 分成 k 个连续的部分, x 中的每个元素都必须完全属于*** 1 个部分。设 y1,,yk 分别是各部分元素的 XOR。那么 y1=y2==yk 必须满足。

例如,如果是 x=[1,1,2,3,0] ,可以将其拆分如下: [1],[1],[2,3,0] .事实上是 1=1=230

给你一个数组 a1,,an 。你的任务是回答 q 个查询:

Solution

位运算

的性质:若有奇数个区间异或和相等,那么这所有的异或和与之前分别的异或和值相等。

在本题中,若有三个以上的区间异或和是相等的,则这三个区间可以合并成一个区间,且异或和与之前一样。

由于本题要求 k>1,则本题 k 的范围只有 k=2 or k=3。若 k>3 ,则一定可以通过上面的方法使得 k3

si 代表前缀异或和

k=2 时,则可以将该区间分为异或和相等的两部分 [l,m],[m+1,r],则 smsl1=sm+1srsl1=sr

k=3 时,则将区间分为 [l,t],[t+1,m],[m+1,r],则 stsl1=smst and smst=srsm

sm=sl1 and sr=st (t<m)

要使得满足这个条件,就得让得到的 t 尽可能小,m 尽可能大,在值相等的前提下, 让 tl 的最小下标,m<r 的最大下标

这里我记反了,lower_bound 是第一个大于等于的元素,uppper_bound 是第一个大于的元素

void solve() {
    int n, q;cin >> n >> q;vector<int> a(n + 1), s(n + 1);
    map<int, vector<int>>mp;
    mp[0].push_back(0);
    for (int i = 1;i <= n;i++) {
        cin >> a[i];s[i] = s[i - 1] ^ a[i];
        mp[s[i]].push_back(i);
    }

    while (q--) {
        int l, r;cin >> l >> r;
        if (s[r] == s[l - 1]) {
            cout << "Yes\n";
        } else {
            auto t = *lower_bound(mp[s[r]].begin(), mp[s[r]].end(), l);
            auto m = *--lower_bound(mp[s[l - 1]].begin(), mp[s[l - 1]].end(), r);
            if (t < m) {
                cout << "Yes\n";
            } else {
                cout << "No\n";
            }
        }
    }
    cout << '\n';
}

G. Division + LCP

给你一个字符串 s 。对于固定的 k ,考虑将 s 恰好分成 k 个连续的子串 w1,,wk 。设 fk 是所有分割中最大可能的 LCP(w1,,wk)

LCP(w1,,wm) 是字符串 w1,,wm 的最长公共前缀的长度。

例如,如果 s=abababcabk=4 ,可能的除法是 abababcab 。由于 ab 是这四个字符串的最长公共前缀,所以 LCP(ab,ab,abc,ab) 就是 2 。请注意,每个子串都由一段连续的字符组成,每个字符都属于**个子串。

您的任务是找出 fl,fl+1,,fr

Solution

Z 算法(扩展 KMP 算法)+二分/字符串算法/LCP

字符串算法我觉得可以放一下

(待更 )