Title

牛客练习赛131(A~C)

小H学语文

排序 枚举 贪心

思路

排序,枚举哪一个最短,注意同时记录下标

神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int maxn = 2e5 + 5;
const int inf = 0x7f7f7f7f;
struct Node
{
    int len;
    int id;
} nums[maxn];

bool cmp(Node a, Node b)
{
    if (a.len != b.len)
    {
        return a.len < b.len;
    }
    else
    {
        return a.id < b.id;
    }
}

void solve()
{
    int n = 0;
    std::cin >> n;
    int pos = 0;
    for (int i = 1; i <= n; i++)
    {
        std::cin >> nums[i].len;
        nums[i].id = i;
    }
    std::sort(nums + 1, nums + 1 + n, cmp);
    int mx = 0;
    for (int i = 1; i <= n; i++)
    {
        int tmp = nums[i].len * (n - i + 1) * (n - i + 1);
        if (tmp > mx)
        {
            mx = tmp;
            pos = i;
        }
    }
    std::cout << n - pos + 1 << endl;
    std::vector<int> t;
    for (int i = pos; i <= n; i++)
    {
        t.push_back(nums[i].id);
    }
    std::sort(t.begin(), t.end());
    for (auto x : t)
    {
        std::cout << x << " ";
    }
}

小H学数学

dp 暴力

思路

范围较小,可以把每个人单独看

\(dpp[i][j]\)表示前\(i\)个人能表示\(j\)的方法数

因为有负数,要设置一个偏移量\(N = 10^3\)

然后分成两次去枚举,一次是用两只手表示一个数,一次是用两只手表示两个数

代码

神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int maxn = 2e5 + 5;
const int inf = 0x7f7f7f7f;
const int mod = 1e9 + 7;
// dp[i][j] 第i步达到j的方案数

int c[11] = {0, 9, 8, 7, 6, 5, 6, 5, 4, 3, 2};
int dp[110][2020];
const int N = 1e3;

void add(int x, int y, int w)
{
    if (y + w >= 0 && y + w <= 2 * N)
    {
        dp[x][y] += dp[x - 1][y + w], dp[x][y] %= mod;
    }
}

void solve()
{
    int x = 0, y = 0;
    std::cin >> x >> y;
    dp[0][N] = 1;
    for (int i = 1; i <= y + 1; i++)
    {
        for (int j = 0; j <= 2 * N; j++)
        {
            for (int k = 1; k <= 10; k++)
            {
                add(i, j, k);
                add(i, j, -k); 
            }
            for (int k1 = 1; k1 <= 5; k1++)
            {
                for (int k2 = 1; k2 <= 5; k2++)
                {
                    add(i, j, k1 + k2);
                    add(i, j, k1 - k2);
                    add(i, j, -k1 - k2);
                    add(i, j, -k1 + k2);
                }
            }
        }
    }
    std::cout << dp[y + 1][x + N] << endl;
}

赛时想法 把一个人能表达的数的方法数求出来

int c[11] = {10, 9, 8, 7, 6, 5, 6, 5, 4, 3, 2};

这个时候\(0\)也要算,因为两只手能把\(0\)表示出来

神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int maxn = 2e5 + 5;
const int inf = 0x7f7f7f7f;
const int mod = 1e9 + 7;
// dp[i][j] 第i步达到j的方案数

int c[11] = {10, 9, 8, 7, 6, 5, 6, 5, 4, 3, 2};
int dp[110][2020];
const int N = 1e3;
void solve()
{
    int x = 0, y = 0;
    std::cin >> x >> y;
    dp[0][1000] = 1;
    for (int i = 1; i <= y + 1; i++)
    {
        for (int j = 0; j <= 2 * N; j++)
        {
            for (int k = 0; k <= 10; k++)
            {
                dp[i][j - k] += (dp[i - 1][j] * c[k] % mod) % mod; dp[i][j - k] %= mod;
                if (k == 0) continue;
                dp[i][j + k] += (dp[i - 1][j] * c[k] % mod) % mod; dp[i][j - k] %= mod;
            }
        }
    }
    std::cout << dp[y + 1][x + 1000] % mod << endl;
}

小H学生物

思维 位运算 \(dfs\)

思路

\(D_{i, j}\) = \(D_{1, i}\oplus D_{1, j}\)

\(\bigoplus\limits_{i = 1}^{m - 2}\bigoplus\limits_{j = i + 2}^{m}D_{a_i, a_j}\)就可以转化为\(\bigoplus\limits_{i = 1}^{m - 2}\bigoplus\limits_{j = i + 2}^{m}D_{1, a_i}\oplus D_{1, a_j}\)
我们只需要计算各个数在表达式中出现的次数就好了

瞪眼法?找规律就是 \(a_1和a_m都出现了m - 2次,其他出现了m-3次\)

那么有这样两种情况

  1. \(m\)为奇数,那就只剩下了\(a_1和a_m\)

  2. \(m\)为偶数,那就只剩下了其他的

维护祖先到每一个物种的变异程度

时间复杂度\(O(n)\)

代码

神奇的代码
#include <bits/stdc++.h>
#define endl '\n'
#define int long long
const int maxn = 1e5 + 5;
const int inf = 0x7f7f7f7f;
std::vector<int> tree[maxn];
std::string d[maxn];
int n = 0, m = 0, L = 0;
std::string sxor(std::string s, std::string t)
{
    std::string res(L, '0');
    for (int i = 0; i < L; i++)
    {
        if (s[i] == t[i])
        {
            res[i] = '0';
        }
        else
        {
            res[i] = '1';
        }
    }
    return res;
}

void dfs(int root)
{
    for (int i = 0; i < tree[root].size(); i++)
    {
        int t = tree[root][i];
        d[t] = sxor(d[t], d[root]);
        dfs(t);
    }
}

void solve()
{
    std::cin >> n >> m >> L;
    int u = 0, v = 0;
    for (int i = 1; i <= n - 1; i++)
    {
        std::cin >> u >> v >> d[v];
        tree[u].push_back(v);
    }
    int tmp = 0;
    d[1] = std::string (L, '0');
    std::vector<int> id(m + 1, 0);
    for (int i = 1; i <= m; i++)
    {
        std::cin >> id[i];
    }
    dfs(1);
    if (m & 1)
    {
        std::cout << sxor(d[id[1]], d[id[m]]) << endl;
    }
    else
    {
        std::string ans (L, '0');
        for (int i = 2; i <= m - 1; i++)
        {
            ans = sxor(ans, d[id[i]]);
        }
        std::cout << ans << endl;
    }
}

小trick 可以使用\(bitset\)直接进行异或操作

神奇的代码
std::vector<int> tree[maxn];
std::bitset<100> d[maxn];
std::bitset<100> ans;
int n = 0, m = 0, L = 0;
void dfs(int root)
{
    for (int i = 0; i < tree[root].size(); i++)
    {
        int t = tree[root][i];
        d[t] ^= d[root];
        dfs(t);
    }
}
void solve()
{
    std::cin >> n >> m >> L;
    int u = 0, v = 0;
    for (int i = 1; i <= n - 1; i++)
    {
        std::cin >> u >> v >> d[v];
        tree[u].push_back(v);
    }
    int tmp = 0;
    std::vector<int> id(m + 1, 0);
    for (int i = 1; i <= m; i++)
    {
        std::cin >> id[i];
    }
    dfs(1);
    if (m & 1)
    {
        ans = d[id[1]] ^ d[id[m]];
    }
    else
    {
        for (int i = 2; i <= m - 1; i++)
        {
            ans ^= d[id[i]];
        }
    }
    std::cout << ans.to_string().substr(100 - L, L) << endl;
}
posted @ 2024-11-02 12:33  栗悟饭与龟功気波  阅读(55)  评论(0)    收藏  举报