2023杭电暑假多校2 题解 | JorbanS

1-Alice Game

题意 n 个怪物排成一排,每次选择下列操作之一,Alice 先手

  • 选择长度小于等于 k 的连续序列,kill 选择的怪物
  • 选择长度为 k 的连续序列,kill 这些怪物,并且将两侧的非空序列独立为俩序列

Tag sg 打表找规律

题解 首先枚举,可知 x <= k 时候永远能使得 Alice 胜利,x = k + 1 时候,永远是 Bob 胜利,因此先看第二次操作

先打表找规律,f 是记忆化搜索,依次枚举 i,得到 j = x - i - k,递归算出每个点的 sg 值,最后取 mex

---========-------
 i    k       j
#include <iostream>
#include <cstring>
#include <set>

using namespace std;
const int N = 1e5 + 2;

int k, f[N];

int sg(int x) {
    if (f[x] != -1) return f[x];
    set<int> s;
    for (int i = 1; i <= x; i ++) {
        int j = x - i - k;
        if (j <= 0) continue;
        s.insert(sg(i) ^ sg(j));
    }
    for (int i = 0; ; i ++)
        if (!s.count(i))
            return f[x] = i;
}

int main() {
    memset(f, -1, sizeof(f));
    cin >> k;
    f[0] = f[k + 1] = 0;
    for (int i = 1; i <= k; i ++) f[i] = 1;
    for (int i = k + 1; i <= 1000; i ++) f[i] = sg(i);
    for (int i = 1; i <= 1000; i ++) {
        if (f[i]) continue;
        cout << i << ' ' << f[i] << endl;
    }
}

在这里插入图片描述

由于打表很慢,总结出规律可直接写结果,极大降低复杂度

#include <iostream>

using namespace std;

int main() {
    int T; cin >> T;
    while (T--) {
        int n, k;
        cin >> k >> n;
        int len = k * 4 + 2;
        n %= len;
        if (n == 0) n = len;
        if (n == k + 1) puts("Bob");
        else puts("Alice");
    }
}

2-Binary Number

题意 给定 01 序列,进行 k 次翻转操作(0110),找出操作后的最大字典序序列

题解 需要多次特判

#include <iostream>

using namespace std;
typedef long long ll;
int n, m;

string solve() {
    ll n, k; cin >> n >> k;
    string s; cin >> s;
    if (k == 0) return s;
    string ans = s;
    int idx = 0, cnt = 0;
    for (int i = 1; i < n; i ++) {
        if (s[i] == '1') cnt ++;
        if (k == 0 && s[i] == '1') break;
        if (s[i] == '0') {
            if (s[i - 1] == '1') k --;
            ans[i] = '1';
        }
    }
    if (cnt == n - 1 && k == 1 || n == 1 && k & 1)
        ans[n - 1] = '0';
    return ans;
}

int main() {
    int T; cin >> T;
    while (T --) cout << solve() << endl;
    return 0;
}

4-Card Game

题意 汉诺塔,但是给定有多少个塔,计算能放的最多盘子

Tag 快速幂

题解 枚举后发现答案为 2 n − 1 − 1 2^{n - 1} - 1 2n11,快速幂即可

#include <iostream>
#define endl '\n'

using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
const int mod = 998244353;
int n, m;

int qpow(int a, int k) {
    int res = 1;
    while (k) {
        if (k & 1) res = (ll)res * a % mod;
        a = (ll)a * a % mod;
        k >>= 1;
    }
    return res;
}

int main() {
    int T; cin >> T;
    while (T --) {
        int x; cin >> x;
        cout << (qpow(2, x - 1) - 1 + mod) % mod << '\n';
    }
    return 0;
}

7-foreverlasting and fried-chicken

题意 左上角为目标图形,右下角为样例图,求所给图中有多少个目标图形

题解 如样例,枚举特征点 18,再找有多少个公共点,最后组合数和乘法原理求解,可以用快速幂求逆元,也可直接 __int128,🤣🤣🤣,赛时用的 vector 一直 TLE,换成 bitset 能极大优化复杂度,bitset的使用详见->

在这里插入图片描述

#include <iostream>
#include <vector>
#include <set>
#include <bitset>
#define endl '\n'

using namespace std;
typedef long long ll;
const int N = 1e3 + 2, mod = 1e9 + 7;
int n, m, last;
bitset<N> bt[N];

ll C2(ll x) {
    return x * (x - 1) / 2 % mod;
}

ll C4(ll xx) {
    __int128 x = xx;
    __int128 res = x * (x - 1) * (x - 2) * (x - 3) / 24 % mod;
    ll ans = res;
    return ans;
}

ll solve() {
    cin >> n >> m;
    ll res = 0;
    for (int i = 1; i <= n; i ++) bt[i].reset();
    for (int i = 0; i < m; i ++) {
        int a, b; cin >> a >> b;
        bt[a][b] = bt[b][a] = 1;
    }
    for (int i = 1; i <= n; i ++) {
        for (int j = 1; j <= n; j ++) {
            int cnt_i = bt[i].count();
            int cnt_j = bt[j].count();
            if (bt[i][j]) cnt_i --, cnt_j --;
            int cnt = (bt[i] & bt[j]).count();
            if (cnt_i < 6 || cnt < 4 || j == i) continue; 
            (res += C2(cnt_i - 4) * C4(cnt)) %= mod;
        }
    }
    return res;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    int T; cin >> T;
    while (T --) cout << solve() << endl;
    return 0;
}

9-String Problem

题意 计算连续的子串的 len,求最大 ∑ K i = 1 l e n ( s i ) − K \sum_{K}^{i = 1} len(s_{i} ) - K Ki=1len(si)K

#include<iostream>

using namespace std;
int solve() {
    string s; cin >> s;
    int res = 0, cnt = 1;
    for (int i = 1; i < s.size(); i++) {
        if (s[i] == s[i - 1]) cnt ++;
        else {
            res += cnt - 1;
            cnt = 1;
        }
    }
    if (cnt) res += cnt - 1;
    return res;
}
signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    int T; cin >> T;
    while (T --) cout << solve() << endl;
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

JorbanS

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值