YAOI Summer Round #4 (Div.2) 题解

前言

个人认为比普及组难度要略低,但实际测试结果极不理想。

题解

以下是这场比赛的各题题解。

#5101. YAOI Summer Round #4 (Div 2) A. 子串之美

得分率正常。

对于 \(20\%\) 的数据,考虑直接枚举子串,再加上一些剪枝,考场上果然也没人写。

对于 \(50\%\) 的数据,考虑用 KMP 算法去统计每个子串,可以做到 \(O(n\log n)\) 的复杂度。

对于另外 \(10\%\) 的数据,显然 a 是出现次数最多的非空子串,出现次数为 \(n\)

对于 \(100\%\) 的数据,显然出现次数最多的非空子串长度为 \(1\),于是用桶存一下每个字母的出现次数即可。

#include <bits/stdc++.h>
#define Re register
using namespace std;

int n, d[31], ans;
char s[10000005];

int main() {
    scanf("%d", &n);
    scanf("%s", s + 1);
    for (Re int i = 1; i <= n; i++) {
        d[s[i] - 'a']++;
    }
    for (Re int i = 0; i < 26; i++) {
        ans = max(ans, d[i]);
    }
    printf("%d", ans);
    return 0;
}

#5102. YAOI Summer Round #4 (Div 2) B. 集合与映射

得分率略低于预期。

对于 \(30\%\) 的数据,分别求出 \(A,B,C\) 即可,复杂度为 \(O(n^2)\)

对于另外 \(20\%\) 的数据,有 \(10\%\) 为单调递增,有 \(10\%\) 为单调递减。

单调递增的那部分,显然可以得到答案为 \(0\)

单调递减的那部分,如果有用心去算的话,很容易发现是序列的逆序对数。

对于 \(100\%\) 的数据,我们通过大力分类讨论(大体上分出了 \(7\) 类,读者可以尝试自行证明),可以证明就是序列中逆序对的数量。

故可以在 \(O(n\log n)\) 的复杂度内完成本题。

#include <bits/stdc++.h>
#define Re register
using namespace std;

typedef long long ll;
const int N = 1000005;
int n, f[N];
ll c[N], ans;

inline int lb(int x) { return x & -x; }

inline void add(int p) {
    for (; p <= n; p += lb(p)) c[p]++;
}

inline ll qry(int p) {
    ll res = 0;
    for (; p; p -= lb(p)) res += c[p];
    return res;
}

int main() {
    scanf("%d", &n);
    for (Re int i = 1; i <= n; i++) {
        scanf("%d", &f[i]);
    }
    for (Re int i = 1; i <= n; i++) {
        add(f[i]);
        ans += i - qry(f[i]);
    }
    printf("%lld", ans);
    return 0;
}

#5103. YAOI Summer Round #4 (Div 2) C. 取物游戏

得分率远低于预期。

对于 \(20\%\) 的数据,直接模拟题意爆搜即可。

对于 \(50\%\) 的数据,是写正解做法被卡时间或空间所得到的分。

对于 \(100\%\) 的数据,考虑设 \(dp[i][j][k][0/1]\) 表示在点 \((i,j)\) 处,差值为 \(k\),这一步是 Alice 取还是 Bob 取的方案数。(如果状态不小心多设了一维,就变成 \(50\%\) 的那一档)

转移很容易想到,具体见代码。

时间复杂度为 \(O(nmk)\),空间复杂度为 \(O(nmk)\)

#include <bits/stdc++.h>
#define Re register
using namespace std;

const int N = 605, K = 35;
const int mod = 1000000007;

int n, m, k, ans;
int a[N][N];
int dp[N][N][K][2];

int main() {
    scanf("%d%d%d", &n, &m, &k);
    for (Re int i = 1; i <= n; i++) {
        for (Re int j = 1; j <= m; j++) {
            scanf("%d", &a[i][j]);
            a[i][j] %= k;
            dp[i][j][a[i][j]][1] = 1;
        }
    }
    for (Re int i = 1; i <= n; i++) {
        for (Re int j = 1; j <= m; j++) {
            for (Re int s = k; s >= 0; s--) {
                (dp[i][j][s][1] += dp[i - 1][j][(s + k - a[i][j]) % k][0]) %= mod;
                (dp[i][j][s][1] += dp[i][j - 1][(s + k - a[i][j]) % k][0]) %= mod;
                (dp[i][j][s][0] += dp[i - 1][j][(s + a[i][j]) % k][1]) %= mod;
                (dp[i][j][s][0] += dp[i][j - 1][(s + a[i][j]) % k][1]) %= mod;
            }
        }
    }
    for (Re int i = 1; i <= n; i++) {
        for (Re int j = 1; j <= m; j++) {
            ans = (ans + dp[i][j][0][0]) % mod;
        }
    }
    printf("%d", ans);
    return 0;
}

#5104. YAOI Summer Round #4 (Div 2) D. 矩阵

得分率远低于预期。

首先,我们会意识到令所有的 \(\max(x,y)\bmod\min(x,y)=1\) 不劣,下面再进行讨论。

对于 \(20\%\) 的数据,通过计算器容易构造出一组解。(从左到右从上到下构造即可)

对于 \(40\%\) 的数据,考虑像国际象棋那样黑白染色,染黑色的取互不相同的质数,染白色的取周围 \(4\) 个黑色格子中数的乘积即可。

对于 \(100\%\) 的数据,实际上与 \(40\%\) 类似,只需要把质数的相对位置进行微调,让大的两个和小的两个配在一起就好了。

复杂度 \(O(n^2)\)

#include <bits/stdc++.h>
#define Re register
using namespace std;

typedef long long ll;

const int N = 505, TOT = 10000005;

int n, tot, p[TOT];
bool vis[TOT];
ll a[N][N];

inline void prework(int mxn) {
    vis[1] = 1;
    for (Re int i = 2; i <= mxn; i++) {
        if (!vis[i])
            p[++tot] = i;
        for (Re int j = 1; j <= tot && i * p[j] <= mxn; j++) {
            vis[i * p[j]] = 1;
            if (i % p[j] == 0)
                break;
        }
    }
}

inline ll gcd(ll x, ll y) { return y == 0 ? x : gcd(y, x % y); }

inline ll lcm(ll x, ll y) {
    if (x == 0 || y == 0)
        return x + y;
    return 1ll * x / gcd(x, y) * y;
}

int main() {
    prework(10000000);
    scanf("%d", &n);
    if (n == 2) {
        printf("4 7\n");
        printf("23 10\n");
        return 0;
    }
    for (Re int i = 1; i <= n; i++) {
        for (Re int j = 1; j <= n; j++) {
            if ((i + j) % 2 == 0) {
                a[i][j] = 1ll * p[(i + j) / 2] * p[n + (n + 1) / 2 + (i - j) / 2];
            }
        }
    }
    for (Re int i = 1; i <= n; i++) {
        for (Re int j = 1; j <= n; j++) {
            if ((i + j) % 2 == 1) {
                a[i][j] = lcm(lcm(a[i - 1][j], a[i][j - 1]), lcm(a[i + 1][j], a[i][j + 1])) + 1;
            }
        }
    }
    for (Re int i = 1; i <= n; i++) {
        for (Re int j = 1; j <= n; j++) {
            printf("%lld ", a[i][j]);
        }
        puts("");
    }
    return 0;
}
posted @ 2021-08-20 17:29  kebingyi  阅读(120)  评论(0编辑  收藏  举报