2023牛客暑期多校训练营4 AFHJL

比赛链接

A

题解

知识点:KMP,构造。

考虑构造全 0,1 串,至少有一个可行。

我们只需要考虑到 t 的border t ,即 t+s+t

  1. t+s+t 总长小于等于 t ,显然成立。
  2. 否则, 若 t+s+t 中有子串等于 t ,那么这个子串不会完整包含前后两端的 t ,这时border就会相交,产生连锁反应,可以证得 t 是全 0,1 串,此时显然成立。
  3. 若没有子串等于 t ,则直接可行。

因此,我们只需要构造两次检查一下即可,检查方式有KMP、Z函数、哈希等等。

时间复杂度 O(n)

空间复杂度 O(n)

代码

#include <bits/stdc++.h>using namespace std;using ll = long long; class KMP { int m; string p; vector<int> nxt; public: KMP() {} KMP(const string &_p) { init(_p); } void init(const string &_p) { m = _p.size() - 1; p = _p; nxt.assign(m + 1, 0); for (int i = 2;i <= m;i++) { nxt[i] = nxt[i - 1]; while (nxt[i] && p[i] != p[nxt[i] + 1]) nxt[i] = nxt[nxt[i]]; nxt[i] += p[i] == p[nxt[i] + 1]; } } vector<int> find(const string &s) { int n = s.size() - 1; vector<int> pos; for (int i = 1, j = 0;i <= n;i++) { while (j && s[i] != p[j + 1]) j = nxt[j]; j += s[i] == p[j + 1]; if (j == m) { pos.push_back(i - j + 1); j = nxt[j]; } } return pos; } vector<int> get_cycle_time() { vector<int> res; int pos = m; while (pos) { pos = nxt[pos]; res.push_back(m - pos); } return res; } vector<int> get_cycle_loop() { vector<int> res; for (auto val : get_cycle_time()) if (!(m % val)) res.push_back(val); return res; } int min_cycle_loop() { return get_cycle_loop()[0]; } void debug() { for (int i = 1;i <= m;i++) cout << nxt[i] << " \n"[i == m]; }};/// KMP,前缀函数O(|P|)、查找O(|S|+|P|)、循环相关O(|P|),维护字符串前缀函数 bool solve() { int n; cin >> n; string t; cin >> t; KMP kmp("?" + t); if (kmp.find("?" + t + string(n, '0') + t).size() <= 2) cout << string(n, '0') << '\n'; else cout << string(n, '1') << '\n'; return true;} int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int t = 1; cin >> t; while (t--) { if (!solve()) cout << -1 << '\n'; } return 0;}
#include <bits/stdc++.h>using namespace std;using ll = long long; class KMP {    int m;    string p;    vector<int> nxt; public:    KMP() {}    KMP(const string &_p) { init(_p); }     void init(const string &_p) {        m = _p.size() - 1;        p = _p;        nxt.assign(m + 1, 0);        for (int i = 2;i <= m;i++) {            nxt[i] = nxt[i - 1];            while (nxt[i] && p[i] != p[nxt[i] + 1]) nxt[i] = nxt[nxt[i]];            nxt[i] += p[i] == p[nxt[i] + 1];        }    }     vector<int> find(const string &s) {        int n = s.size() - 1;        vector<int> pos;        for (int i = 1, j = 0;i <= n;i++) {            while (j && s[i] != p[j + 1]) j = nxt[j];            j += s[i] == p[j + 1];            if (j == m) {                pos.push_back(i - j + 1);                j = nxt[j];            }        }        return pos;    }     vector<int> get_cycle_time() {        vector<int> res;        int pos = m;        while (pos) {            pos = nxt[pos];            res.push_back(m - pos);        }        return res;    }     vector<int> get_cycle_loop() {        vector<int> res;        for (auto val : get_cycle_time())            if (!(m % val)) res.push_back(val);        return res;    }    int min_cycle_loop() { return get_cycle_loop()[0]; }     void debug() {        for (int i = 1;i <= m;i++)            cout << nxt[i] << " \n"[i == m];    }};/// KMP,前缀函数O(|P|)、查找O(|S|+|P|)、循环相关O(|P|),维护字符串前缀函数 bool solve() {    int n;    cin >> n;    string t;    cin >> t;    KMP kmp("?" + t);    if (kmp.find("?" + t + string(n, '0') + t).size() <= 2) cout << string(n, '0') << '\n';    else cout << string(n, '1') << '\n';    return true;} int main() {    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);    int t = 1;    cin >> t;    while (t--) {        if (!solve()) cout << -1 << '\n';    }    return 0;}
#include <bits/stdc++.h>using namespace std;using ll = long long; class KMP { int m; string p; vector<int> nxt; public: KMP() {} KMP(const string &_p) { init(_p); } void init(const string &_p) { m = _p.size() - 1; p = _p; nxt.assign(m + 1, 0); for (int i = 2;i <= m;i++) { nxt[i] = nxt[i - 1]; while (nxt[i] && p[i] != p[nxt[i] + 1]) nxt[i] = nxt[nxt[i]]; nxt[i] += p[i] == p[nxt[i] + 1]; } } vector<int> find(const string &s) { int n = s.size() - 1; vector<int> pos; for (int i = 1, j = 0;i <= n;i++) { while (j && s[i] != p[j + 1]) j = nxt[j]; j += s[i] == p[j + 1]; if (j == m) { pos.push_back(i - j + 1); j = nxt[j]; } } return pos; } vector<int> get_cycle_time() { vector<int> res; int pos = m; while (pos) { pos = nxt[pos]; res.push_back(m - pos); } return res; } vector<int> get_cycle_loop() { vector<int> res; for (auto val : get_cycle_time()) if (!(m % val)) res.push_back(val); return res; } int min_cycle_loop() { return get_cycle_loop()[0]; } void debug() { for (int i = 1;i <= m;i++) cout << nxt[i] << " \n"[i == m]; }};/// KMP,前缀函数O(|P|)、查找O(|S|+|P|)、循环相关O(|P|),维护字符串前缀函数 bool solve() { int n; cin >> n; string t; cin >> t; KMP kmp("?" + t); if (kmp.find("?" + t + string(n, '0') + t).size() <= 2) cout << string(n, '0') << '\n'; else cout << string(n, '1') << '\n'; return true;} int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int t = 1; cin >> t; while (t--) { if (!solve()) cout << -1 << '\n'; } return 0;}

F

题解

知识点:二分,贪心。

显然每次只有最小值和最大值会被票出。

具体来说,我们统计最大值和最小值中点左右两侧的人数,左侧一定给最大值票,右侧一定给最小值票。当左大于等于右时,最大值会被票出,否则最小值会被票出。

因此,我们排序后,用二分找到中点的位置,用双指针表示当前剩余区间。

时间复杂度 O(nlogn)

空间复杂度 O(n)

代码

#include <bits/stdc++.h>using namespace std;using ll = long long; int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; vector<pair<int, int>> a(n + 1); for (int i = 1;i <= n;i++) { int x; cin >> x; a[i] = { x,i }; } sort(a.begin() + 1, a.end()); int l = 1, r = n; for (int i = 1;i <= n - 1;i++) { int mid = a[l].first + a[r].first >> 1; int it = upper_bound(a.begin() + l, a.begin() + r + 1, pair<int, int>{ mid, 2e9 }) - a.begin(); int lval = it - l; int rval = r - it + 1; if (lval >= rval) r--; else l++; } cout << a[l].second << '\n'; return 0;}
#include <bits/stdc++.h>using namespace std;using ll = long long; int main() {    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);    int n;    cin >> n;    vector<pair<int, int>> a(n + 1);    for (int i = 1;i <= n;i++) {        int x;        cin >> x;        a[i] = { x,i };    }    sort(a.begin() + 1, a.end());     int l = 1, r = n;    for (int i = 1;i <= n - 1;i++) {        int mid = a[l].first + a[r].first >> 1;        int it = upper_bound(a.begin() + l, a.begin() + r + 1, pair<int, int>{ mid, 2e9 }) - a.begin();        int lval = it - l;        int rval = r - it + 1;        if (lval >= rval) r--;        else l++;    }    cout << a[l].second << '\n';    return 0;}
#include <bits/stdc++.h>using namespace std;using ll = long long; int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; vector<pair<int, int>> a(n + 1); for (int i = 1;i <= n;i++) { int x; cin >> x; a[i] = { x,i }; } sort(a.begin() + 1, a.end()); int l = 1, r = n; for (int i = 1;i <= n - 1;i++) { int mid = a[l].first + a[r].first >> 1; int it = upper_bound(a.begin() + l, a.begin() + r + 1, pair<int, int>{ mid, 2e9 }) - a.begin(); int lval = it - l; int rval = r - it + 1; if (lval >= rval) r--; else l++; } cout << a[l].second << '\n'; return 0;}

H

题解

知识点:构造。

尝试在正方形对角线上选择一点,将正方形分为左上正方形,右下正方形和两个对称的长方形。

然后,按照类似gcd的方式,对长方形进行划分正方形。

可以统计得到一定存在一点,使得长方形划分后的正方形数量不超过 24 ,即总和不超过 50

因此,我们递归执行两种操作即可。

时间复杂度 O(n2)

空间复杂度 O(n2)

代码

#include <bits/stdc++.h>using namespace std;using ll = long long; int gcd(int a, int b, int &cnt) { if (b) { cnt += a / b; return gcd(b, a % b, cnt); } else return a;} vector<tuple<int, int, int>> ans; void dfs_rec(int x, int y, int a, int b);void dfs_sqr(int x, int y, int a); void dfs_rec(int x, int y, int a, int b) { bool sw = a < b; if (sw) swap(x, y), swap(a, b); if (!b) return; for (int i = b;i <= a;i += b) { if (sw) dfs_sqr(y, x + i - b, b); else dfs_sqr(x + i - b, y, b); } if (sw) dfs_rec(y, x + a / b * b, b, a % b); else dfs_rec(x + a / b * b, y, a % b, b);} void dfs_sqr(int x, int y, int a) { if (a == 1) return; if (a <= 7) { ans.push_back({ x,y,a }); return; } bool ok = 0; for (int i = 1;i <= a - 1;i++) { int cnt = 0; gcd(i, a - i, cnt); if (cnt >= 25) continue; ok = 1; dfs_sqr(x, y, i); dfs_rec(x + i, y, a - i, i); dfs_rec(x, y + i, i, a - i); dfs_sqr(x + i, y + i, a - i); break; } assert(ok); ans.push_back({ x,y,a });} int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; dfs_sqr(1, 1, n); cout << ans.size() << '\n'; for (auto [x, y, a] : ans) cout << x << ' ' << y << ' ' << a << '\n'; return 0;}
#include <bits/stdc++.h>using namespace std;using ll = long long; int gcd(int a, int b, int &cnt) {    if (b) {        cnt += a / b;        return gcd(b, a % b, cnt);    }    else return a;} vector<tuple<int, int, int>> ans; void dfs_rec(int x, int y, int a, int b);void dfs_sqr(int x, int y, int a); void dfs_rec(int x, int y, int a, int b) {    bool sw = a < b;    if (sw) swap(x, y), swap(a, b);    if (!b) return;    for (int i = b;i <= a;i += b) {        if (sw) dfs_sqr(y, x + i - b, b);        else dfs_sqr(x + i - b, y, b);    }    if (sw) dfs_rec(y, x + a / b * b, b, a % b);    else dfs_rec(x + a / b * b, y, a % b, b);} void dfs_sqr(int x, int y, int a) {    if (a == 1) return;    if (a <= 7) {        ans.push_back({ x,y,a });        return;    }    bool ok = 0;    for (int i = 1;i <= a - 1;i++) {        int cnt = 0;        gcd(i, a - i, cnt);        if (cnt >= 25) continue;        ok = 1;        dfs_sqr(x, y, i);        dfs_rec(x + i, y, a - i, i);        dfs_rec(x, y + i, i, a - i);        dfs_sqr(x + i, y + i, a - i);        break;    }    assert(ok);    ans.push_back({ x,y,a });} int main() {    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);    int n;    cin >> n;    dfs_sqr(1, 1, n);    cout << ans.size() << '\n';    for (auto [x, y, a] : ans) cout << x << ' ' << y << ' ' << a << '\n';    return 0;}
#include <bits/stdc++.h>using namespace std;using ll = long long; int gcd(int a, int b, int &cnt) { if (b) { cnt += a / b; return gcd(b, a % b, cnt); } else return a;} vector<tuple<int, int, int>> ans; void dfs_rec(int x, int y, int a, int b);void dfs_sqr(int x, int y, int a); void dfs_rec(int x, int y, int a, int b) { bool sw = a < b; if (sw) swap(x, y), swap(a, b); if (!b) return; for (int i = b;i <= a;i += b) { if (sw) dfs_sqr(y, x + i - b, b); else dfs_sqr(x + i - b, y, b); } if (sw) dfs_rec(y, x + a / b * b, b, a % b); else dfs_rec(x + a / b * b, y, a % b, b);} void dfs_sqr(int x, int y, int a) { if (a == 1) return; if (a <= 7) { ans.push_back({ x,y,a }); return; } bool ok = 0; for (int i = 1;i <= a - 1;i++) { int cnt = 0; gcd(i, a - i, cnt); if (cnt >= 25) continue; ok = 1; dfs_sqr(x, y, i); dfs_rec(x + i, y, a - i, i); dfs_rec(x, y + i, i, a - i); dfs_sqr(x + i, y + i, a - i); break; } assert(ok); ans.push_back({ x,y,a });} int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n; cin >> n; dfs_sqr(1, 1, n); cout << ans.size() << '\n'; for (auto [x, y, a] : ans) cout << x << ' ' << y << ' ' << a << '\n'; return 0;}

J

题解

知识点:线性dp,前缀和。

考虑设 fi,j 为考虑了前 i 个数的后缀(不可为空)最小值为 j 时的方案数。显然, j[m,m] 中。

fi1,j 时,[j,m] 的数字可以被使用,进一步分类讨论转移方程:

  1. j0 时,后缀最小值更新为 ai 本身:

    fi1,jfi,[j,m]

  2. j<0 时,后缀最小值更新为 ai+j

    fi1,jfi,[0,m+j]

用前缀和优化转移即可。

时间复杂度 O(nm)

空间复杂度 O(m)

代码

#include <bits/stdc++.h>using namespace std;using ll = long long; const int P = 998244353;int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n, m; cin >> n >> m; vector<int> f(2 * m + 1); f[2 * m] = 1; for (int i = 0;i < n;i++) { vector<int> g(2 * m + 1); for (int j = -m;j <= m;j++) { if (j >= 0) (g[-j + m] += f[j + m]) %= P; else { (g[0 + m] += f[j + m]) %= P; (g[j + m + m + 1] -= f[j + m] - P) %= P; } } for (int j = -m + 1;j <= m;j++) (g[j + m] += g[j - 1 + m]) %= P; swap(f, g); } int ans = 0; for (int i = -m;i <= m;i++) (ans += f[i + m]) %= P; cout << ans << '\n'; return 0;}
#include <bits/stdc++.h>using namespace std;using ll = long long; const int P = 998244353;int main() {    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);    int n, m;    cin >> n >> m;    vector<int> f(2 * m + 1);    f[2 * m] = 1;    for (int i = 0;i < n;i++) {        vector<int> g(2 * m + 1);        for (int j = -m;j <= m;j++) {            if (j >= 0) (g[-j + m] += f[j + m]) %= P;            else {                (g[0 + m] += f[j + m]) %= P;                (g[j + m + m + 1] -= f[j + m] - P) %= P;            }        }        for (int j = -m + 1;j <= m;j++) (g[j + m] += g[j - 1 + m]) %= P;        swap(f, g);    }    int ans = 0;    for (int i = -m;i <= m;i++) (ans += f[i + m]) %= P;    cout << ans << '\n';    return 0;}
#include <bits/stdc++.h>using namespace std;using ll = long long; const int P = 998244353;int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n, m; cin >> n >> m; vector<int> f(2 * m + 1); f[2 * m] = 1; for (int i = 0;i < n;i++) { vector<int> g(2 * m + 1); for (int j = -m;j <= m;j++) { if (j >= 0) (g[-j + m] += f[j + m]) %= P; else { (g[0 + m] += f[j + m]) %= P; (g[j + m + m + 1] -= f[j + m] - P) %= P; } } for (int j = -m + 1;j <= m;j++) (g[j + m] += g[j - 1 + m]) %= P; swap(f, g); } int ans = 0; for (int i = -m;i <= m;i++) (ans += f[i + m]) %= P; cout << ans << '\n'; return 0;}

L

题解

知识点:离线,枚举。

考虑离线后倒着操作,并统计行的个数。

显然每行每列只关心最后一次操作的类型,之后的操作不需要考虑。

记录列开、列关的列数分别为 cnton,cntoff 。若行操作为打开,答案增加 mcntoff ,否则增加 cnton

最后统计没被操作的行,对于每行答案增加 cnton

时间复杂度 O(n+q)

空间复杂度 O(n+m+q)

代码

#include <bits/stdc++.h>using namespace std;using ll = long long; struct Query { bool row; int id; bool on;}Q[1000007]; bool row_vis[1000007];bool col_vis[1000007];int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n, m, q; cin >> n >> m >> q; for (int i = 1;i <= q;i++) { string row; int id; string on; cin >> row >> id >> on; Q[i] = { row == "row",id,on == "on" }; } ll ans = 0; int cnt_on = 0, cnt_off = 0; for (int i = q;i >= 1;i--) { if (Q[i].row) { if (row_vis[Q[i].id]) continue; ans += Q[i].on ? m - cnt_off : cnt_on; row_vis[Q[i].id] = 1; } else { if (col_vis[Q[i].id]) continue; if (Q[i].on) cnt_on++; else cnt_off++; col_vis[Q[i].id] = 1; } } for (int i = 1;i <= n;i++) if (!row_vis[i]) ans += cnt_on; cout << ans << '\n'; return 0;}
#include <bits/stdc++.h>using namespace std;using ll = long long; struct Query {    bool row;    int id;    bool on;}Q[1000007]; bool row_vis[1000007];bool col_vis[1000007];int main() {    std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);    int n, m, q;    cin >> n >> m >> q;    for (int i = 1;i <= q;i++) {        string row;        int id;        string on;        cin >> row >> id >> on;        Q[i] = { row == "row",id,on == "on" };    }     ll ans = 0;    int cnt_on = 0, cnt_off = 0;    for (int i = q;i >= 1;i--) {        if (Q[i].row) {            if (row_vis[Q[i].id]) continue;            ans += Q[i].on ? m - cnt_off : cnt_on;            row_vis[Q[i].id] = 1;        }        else {            if (col_vis[Q[i].id]) continue;            if (Q[i].on) cnt_on++;            else cnt_off++;            col_vis[Q[i].id] = 1;        }    }    for (int i = 1;i <= n;i++) if (!row_vis[i]) ans += cnt_on;    cout << ans << '\n';    return 0;}
#include <bits/stdc++.h>using namespace std;using ll = long long; struct Query { bool row; int id; bool on;}Q[1000007]; bool row_vis[1000007];bool col_vis[1000007];int main() { std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0); int n, m, q; cin >> n >> m >> q; for (int i = 1;i <= q;i++) { string row; int id; string on; cin >> row >> id >> on; Q[i] = { row == "row",id,on == "on" }; } ll ans = 0; int cnt_on = 0, cnt_off = 0; for (int i = q;i >= 1;i--) { if (Q[i].row) { if (row_vis[Q[i].id]) continue; ans += Q[i].on ? m - cnt_off : cnt_on; row_vis[Q[i].id] = 1; } else { if (col_vis[Q[i].id]) continue; if (Q[i].on) cnt_on++; else cnt_off++; col_vis[Q[i].id] = 1; } } for (int i = 1;i <= n;i++) if (!row_vis[i]) ans += cnt_on; cout << ans << '\n'; return 0;}

© 版权声明
THE END
喜欢就支持一下吧
点赞0

Warning: mysqli_query(): (HY000/3): Error writing file '/tmp/MYHy41Fd' (Errcode: 28 - No space left on device) in /www/wwwroot/583.cn/wp-includes/class-wpdb.php on line 2345
admin的头像-五八三
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

图形验证码
取消
昵称代码图片