Title

牛客周赛Round112

牛客周赛 Round 112

题目链接

写在前面

A. 模拟

B. 思维

C. 思维

D. 位运算贪心

E. 计数原理

F. 状压DP

A. ICPC Regionals

思路

按照题意模拟即可

代码

#include <bits/stdc++.h>
#define endl '\n'
// #define int long long


void solve()
{
    int n = 0, k = 0;
    std::cin >> n >> k;
    int g = (n / 10) + (n % 10 != 0);
    if (k <= g) {std::cout << "Gold Medal"; return;}
    if (k <= 3 * g) {std::cout << "Silver Medal"; return;}
    if (k <= 6 * g) {std::cout << "Bronze Medal"; return;}
    std::cout << "Da Tie";
}

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

B. Card Game

思路

只能出一张牌

  • 丢牌,丢几张牌获得点数为几的牌,肯定丢完能获得最大的点数
  • 不丢牌,就取最大的那一个
  • 两者取最大即可

代码

#include <bits/stdc++.h>
#define endl '\n'
// #define int long long


void solve()
{
    int n = 0; std::cin >> n;
    int mx = -1;
    for (int i = 1; i <= n; i++)
    {
        int tmp; std::cin >> tmp;
        mx = std::max(mx, tmp);
    }
    std::cout << std::max(mx, n) << endl;
}

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

C. Palindrome Coloring

思路

首先我们能注意到:最多操作两次

  • 如果本身就是回文串,就操作一次就行
  • 如果本身不是回文串,第一次把所有1染成红色, 第二次把所有0染成红色,因为相同的数组成的序列一定回文

做条件判断即可

#include <bits/stdc++.h>
#define endl '\n'
// #define int long long


void solve()
{
    std::string s; std::cin >> s;
    int len = s.size();
    int i = 0, j = len - 1;
    while(i < j)
    {
        if (s[i] != s[j])
        {
            std::cout << 2 << endl;
            return;
        }
        i++; j--;
    }   
    std::cout << 1 << endl;
}

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

D. Digital Pairing

思路

按位贪心
在当前可选的数字中,从高位开始,如果位为1的数字 \(\geq n\)的话,这一位就选上,并把这一位为1的数字加入候选数字中参与下一轮筛选就好了,为0的就不用管了

代码

#include <bits/stdc++.h>
#define endl '\n'
#define int long long


void solve()
{
    int n = 0; std::cin >> n;
    std::vector<int> num(n * 2 + 1, 0);
    std::vector<std::vector<int>> bit(n * 2 + 1, std::vector<int>(40, 0));
    for (int i = 1; i <= n * 2; i++)
    {
        int tmp; std::cin >> tmp;
        num[i] = tmp;
        for (int j = 35; j >= 0; j--)
        {
            if ((1LL << j) & tmp) bit[i][j] = 1;
        }
    }
    int ans = 0;
    std::vector<int> id;
    for (int i = 1; i <= n * 2; i++) id.push_back(i);
    for (int i = 35; i >= 0; i--)
    {
        ans <<= 1;
        std::vector<int> tmp;
        int cnt = 0;
        for (int j = 0; j < (int)id.size(); j++)
        {
            if (bit[id[j]][i] == 1) {tmp.push_back(id[j]); cnt++;}
        }
        if (cnt < n) continue;
        ans += 1;
        id = tmp;
    }
    std::cout << ans << endl;
}

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

E. Beautiful Sequence

思路

正难则反,题目要求美丽序列的个数,我们可以求不美丽序列的个数
不美丽序列就是序列中有序列的gcd,我们可以枚举gcd, 序列中一旦有gcd的倍数就一定是不美丽的
对于一个gcd, 加入有\(a\)\(gcd\), \(b\)个它的倍数, 那么产生的不美丽序列个数就是

\[ cnt_{gcd} = (2^a - 1) \times 2^b \]

因为我们枚举的是gcd,所以gcd一定有,所以\(-1\)减掉一个gcd都没有的情况,那么此时它的倍数就可以有也可以没有了

至于枚举gcd的复杂度
\(gcd\)\(1~n\)\(O(n)\)的,枚举倍数是\(O(n + \frac{n}{2} + \frac{n}{3} + \dots + 1)\)
调和级数是\(log\)数量级的,总体时间复杂度\(O(nlogn)\)

代码

#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int mod = 998244353;
int power(int y, int x)
{
    int res = 1;
    while(x)
    {
        if (x & 1)
        {
            res = res * y % mod;
        }
        x >>= 1;
        y = y * y % mod;
    }
    return res;
}

void solve()
{
    int ans = 0;
    int n = 0; std::cin >> n;
    int mp[200010]{};
    for (int i = 1; i <= n; i++)
    {
        int tmp; std::cin >> tmp;
        mp[tmp]++;
    }
    for (int i = 1; i <= n; i++)
    {
        int g = i; int cnt = 0;
        for (; g <= n; g += i)
        {
            cnt += mp[g];
        }
        if (mp[i] == 0 || cnt == 0) continue;
        int tmp = (power(2, mp[i]) - 1 + mod) % mod;
        tmp = tmp * power(2, cnt - mp[i]) % mod;
        ans += tmp;
        ans %= mod;
    }
    // std::cout << ans << endl;
    int tot = power(2, n) - 1;
    tot = (tot + mod) % mod;
    std::cout << (tot - ans + mod) % mod << endl;
}

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

F. Bracket Counting

思路

注意一个合法序列在任意位置左括号数一定大于等于右括号数

找时间再写吧QAQ

代码

#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int mod = 1e9 + 7;

void solve() 
{
    int n = 0; std::cin >> n;
    std::vector<int> bal(n);
    std::vector<int> min_bal(n);
    int tot = 0;
    for (int i = 0; i < n; i++)
    {
        std::string s;
        std::cin >> s;
        int val = 0;
        int current_min = 0;
        for (char c : s)
        {
            if (c == '(') val++;
            else val--; 
            current_min = std::min(current_min, val);
        }
        bal[i] = val;
        min_bal[i] = current_min; 
        tot += val;
    }

    if (tot != 0) {
        std::cout << 0 << endl;
        return;
    }
    std::vector<std::map<int, int>> dp(1 << n);
    
    dp[0][0] = 1; 

    for (int mask = 0; mask < (1 << n); mask++) 
    {
        if (dp[mask].empty()) continue;

        for (auto [x, y] : dp[mask])
        {
            for (int j = 0; j < n; j++)
            {
                if (!(mask & (1 << j)))
                {
                    if (x + min_bal[j] >= 0)
                    {
                        int new_mask = mask | (1 << j);
                        int new_bal = x + bal[j];
                        dp[new_mask][new_bal] = (dp[new_mask][new_bal] + y) % mod;
                    }
                }
            }
        }
    }
    std::cout << dp[(1 << n) - 1][0] << endl;
}

signed main()
{
    std::ios::sync_with_stdio(false);
    std::cout.tie(nullptr); std::cin.tie(nullptr);
    int _t = 1;
    std::cin >> _t;
    while(_t--) solve();
    return 0;
}
posted @ 2025-10-06 00:01  栗悟饭与龟功気波  阅读(14)  评论(0)    收藏  举报