2025河北省赛vp&补题记录

摘要

4题525罚时,收银员
总体来说打的并不好,可能是有点累脑子转不动,中途还睡了一会。
还有一周就省赛了,加油加油!

赛时部分

Problem H. What is all you need?

签到题

赛时写的有点复杂了,曲线救国,说明脑子确实有点不清醒。

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define ll long long
#define pii pair<int, int>
#define endl '\n'

const int mod = 1e9+7, inf = 0x3f3f3f3f;

void solve() {
    string s;
    cin >> s;
    string suf = "isallyouneed";
    reverse(suf.begin(), suf.end());
    reverse(s.begin(), s.end());
    if(s.find(suf) != 0) cout << "No" << endl;
    else {
        cout << "Yes" << endl;
        string ans = s.substr(12, s.size()-12);
        reverse(ans.begin(), ans.end());
        cout << ans << endl;
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t--) solve();
    return 0;
}

Problem K. UNO!

简单模拟,链表

一开始模拟的时候题目读漏了,wa了一发,然后T了,后面学长过来看了一眼说可以双向链表,但是因为本蒟蒻脑子不太清醒,把链表左右接反了,又wa了一发,+3之后终于AC了,所以状态不好影响真的很大qwq。

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define ll long long
#define pii pair<int, int>
#define endl '\n'

const int mod = 1e9+7, inf = 0x3f3f3f3f;

void solve() {
    int n, m;
    cin >> n >> m;
    vector<int> a(n);
    vector<int> left(n), right(n);
    for(int i = 0; i < n; i ++ ) {
        cin >> a[i];
        if(i == 0) {
            left[i] = n-1;
            right[i] = 1;
        } else if(i == n-1) {
            left[i] = i-1;
            right[i] = 0;
        } else {
            left[i] = i-1;
            right[i] = i+1;
        }
    }
    string s;
    cin >> s;
    vector<bool> vis(n, 0);
    int now = 0, st = 0; // 0-left, 1-right
    for(char& c : s) {
        if(c == 'C') {
            a[now]--;
            if(a[now] == 0) {
                int l = left[now];
                int r = right[now];
                left[right[now]] = l;
                right[left[now]] = r;
            }
        } else if(c == 'S') {
            a[now]--;
            if(a[now] == 0) {
                int l = left[now];
                int r = right[now];
                left[right[now]] = l;
                right[left[now]] = r;
            }
            if(!st) now = right[now];
            else now = left[now];
        } else if(c == 'R') {
            a[now]--;
            if(a[now] == 0) {
                int l = left[now];
                int r = right[now];
                left[right[now]] = l;
                right[left[now]] = r;
            }
            st = !st;
        } else {
            a[now]--;
            if(a[now] == 0) {
                int l = left[now];
                int r = right[now];
                left[right[now]] = l;
                right[left[now]] = r;
            }
            if(!st) now = right[now];
            else now = left[now];
            a[now] += 2;
        }
        if(!st) now = right[now];
        else now = left[now];
    }
    for(int i = 0; i < n; i ++ ) cout << a[i] << endl;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t--) solve();
    return 0;
}

Problem J. Generate 01 String

模拟,思维

不难想到每次插入时插入的第一个字符以及前面的都可以当作为以及固定的部分,因此每次插入至少可以确定一个位置的字符,所以只需要遍历一遍目标串,模拟插入即可。
在插入过程中,以遍历到当前的字符为遍历方式,若是'0'则选择方式1,若是'1'则选择方式2,因为只有每次插入的第一个字符是固定的,所以我们可以维护两个变量来统计以及插入进字符串但是没有固定位置的0和1,在遍历时如果当前字符在之前的插入中没有确定位置的数量不为零则直接跳过。
说的可能不太清楚,直接看代码叭。

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define ll long long
#define pii pair<int, int>
#define endl '\n'

const int mod = 1e9+7, inf = 0x3f3f3f3f;

void solve() {
    string str;
    cin >> str;
    int zero = 0, one = 0;
    for(int i = 0; i < str.size(); i ++ ) {
        if(str[i] == '0') zero++;
        else one++;
    }
    if(zero != one) {cout << -1 << endl; return;}
    cout << zero << endl;
    zero = 0, one = 0;
    int s = 1;
    for(int i = 0; i < str.size(); i ++ ) {
        if(str[i] == '1' && one) {
            one--;
            continue;
        } else if(str[i] == '0' && zero) {
            zero--;
            continue;
        }
        if(i > 0 && str[i] != str[i-1]) {
            if(str[i] == '1') {
                cout << s-(one+zero) << ' ' << 2 << endl;
                s++;
                zero++;
            } else {
                cout << s-(one+zero) << ' ' << 1 << endl;
                s++;
                one++;
            }
        } else if(i > 0 && str[i] == str[i-1]) {
            if(str[i] == '1') {
                cout << s-(one+zero) << ' ' << 2 << endl;
                s++;
                zero++;
            } else {
                cout << s-(one+zero) << ' ' << 1 << endl;
                s++;
                one++;
            }
        }
        if(i == 0) {
            if(str[i] == '1') {
                cout << s << ' ' << 2 << endl;
                s++;
                zero++;
            } else {
                cout << s << ' ' << 1 << endl;
                s++;
                one++;
            }
        }
    }
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t--) solve();
    return 0;
}

Problem A. 棋盘

博弈,思维

容易想到在一开始时M和B两人都不会往另一行走,而在最初,因为M先手占据主动,所以可以考虑在一开始什么情况下M必赢。
由于先手,我们可以得知,M可以强行占领n/2个上下格的分数,而如果此时n/2个上下格的分数以及足以让M获得胜利,则直接输出答案。
相同的,B可以强行占领n/2-1个上下格的分数,如果这些格子的分数足以让B获胜,也可以直接输出答案。
在考虑完这两种可能后,就进入了博弈阶段了。
当双方都没有必赢的可能时,便开始考虑平局。我们可以发现,当双方都不回头的时候只有上下各占一半的可能,而题目中表述的很明确,如果无法获胜,会尽可能选择平局,也就是说进入博弈阶段时,当上下各占一半的情况下某一方处于劣势,那么他就会寻找平局的可能,也就是看自己可以稳定抢占的格子能否得到平局,如果可以则直接输出平局。
最后,我们可以发现,所有稳定抢占格子的可能性都已经分析完了,此时只剩下上下各占一半的可能,直接比较上下两部分的前缀和即可。

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define ll long long
#define pii pair<int, int>
#define endl '\n'

const int mod = 1e9+7, inf = 0x3f3f3f3f;

void solve() {
    int n;
    cin >> n;
    vector<vector<int>> a(2, vector<int>(n+1,0));
    for(int i = 1; i <= n; i ++ ) {
        cin >> a[0][i];
        a[0][i] += a[0][i-1];
    }
    for(int i = 1; i <= n; i ++ ) {
        cin >> a[1][i];
        a[1][i] += a[1][i-1];
    }
    auto get_sum = [&](int l, int r) -> ll {
        if(l > r) return 0;
        return a[0][r]+a[1][r]-a[0][l-1]-a[1][l-1];
    };
    int half = n/2;
    int half_ = half+1;
    if(get_sum(1, half) > get_sum(half_, n)) cout << "Mandy" << endl;
    else if(get_sum(1, half_) < get_sum(half_+1, n)) cout << "brz" << endl;
    else if(a[0][n] < a[1][n] && get_sum(1, half) == get_sum(half_, n)) cout << "draw" << endl;
    else if(a[0][n] > a[1][n] && get_sum(1, half_) == get_sum(half_+1, n)) cout << "draw" << endl;
    else if(a[0][n] > a[1][n]) cout << "Mandy" << endl;
    else if(a[0][n] == a[1][n]) cout << "draw" << endl;
    else if(a[0][n] < a[1][n]) cout << "brz" << endl;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    int t = 1;
    cin >> t;
    while(t--) solve();
    return 0;
}

补题部分

Problem M. 第九届河北省大学生程序设计竞赛

枚举,排序,状态压缩

这题赛时的时候看了一眼,感觉可以用状态压缩做,然后就跟队友说了一声,但是两个学长都不会,蒟蒻那时候又太累了直接deepsleep了,直到最后学长的dfs也没调出来。
我们注意到这题的数据范围并不大,而且给出的题目数量不会超过18,也就是说最大18个题目的选择状态可以用2^18次方以内的整数来表示,也就是状态压缩。
接着我们枚举每一种题目选取的组合,也就是从0一直枚举到(1<<n)-1,同时使用__builtin_popcount函数来统计这个组合里边选了多少道题,如果不符合10-13的条件就直接剪掉。
接着我们对每一种合法的题目组合依据每个队伍的过题数进行排序,同时查看r1,r2,r3是否符合条件,如果符合条件就直接输出答案并退出程序即可。

#include <bits/stdc++.h>

using namespace std;

#define int long long
#define ll long long
#define ull unsigned long long
#define pii pair<int, int>
#define pll pair<ll, ll> 

#define endl '\n'
#define Y cout << "YES\n"
#define N cout << "NO\n"

#define fi first
#define se second

const int MOD = 1e9+7, inf = 0x3f3f3f3f;

class RandomGenerator {
private:
    random_device rd;
    mt19937_64 gen;

public:
    RandomGenerator() : rd(), gen(rd()) {}

    ll generateRandomNumber(ll min, ll max) {
        uniform_int_distribution<ll> dis(min, max);
        return dis(gen);
    }

    std::vector<ll> generateRandomArray(ll length, ll min, ll max) {
        vector<ll> arr;
        uniform_int_distribution<ll> dis(min, max);
        for (int i = 0; i < length; ++i) {
            arr.push_back(dis(gen));
        }
        return arr;
    }
};

void Sort(int k, vector<int>& res, int n, int m, vector<string>& team) {
    for(int i = 0; i < n; i ++ ) {
        if((k >> i) & 1) {
            for(int j = 0; j < m; j ++ ) {
                if(team[j][i] == '1') res[j]++;
            }
        }
    }
    sort(res.begin(), res.end(), greater());
}

void solve() {
    int n, m;
    cin >> n >> m;
    vector<string> team(m); 
    for(int i = 0; i < m; i ++ ) cin >> team[i];
    int r1, r2, r3;
    int p1, p2, p3;
    cin >> r1 >> r2 >> r3 >> p1 >> p2 >> p3;
    for(int k = 0; k <= (1 << n)-1; k ++ ) {
        int count = __builtin_popcount(k);
        if(count < 10 || count > 13) continue;
        vector<int> res(m, 0);
        Sort(k, res, n, m, team);
        if(res[r1-1] == p1 && res[r2-1] == p2 && res[r3-1] == p3) {
            cout << count << endl;
            for(int i = 0; i < n; i ++ ) {
                if((k >> i)&1) {
                    cout << i+1 << ' ';
                }
            }
            cout << endl;
            return;
        }
    }
    cout << -1 << endl;
}

signed main() {
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
    int t = 1;
    //cin >> t;
    while(t--) solve();
    return 0;
}
posted @ 2025-05-25 01:34  算法蒟蒻沐小白  阅读(82)  评论(0)    收藏  举报