牛客小白月赛28

比赛链接:https://ac.nowcoder.com/acm/contest/7412

A - 牛牛和牛可乐的赌约

题解

计算模意义下的 $1 - \frac{1}{n^m}$ 即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int MOD = 1e9 + 7;

int binpow(int a, int b) {
    int res = 1;
    while (b > 0) {
        if (b & 1) res = 1LL * res * a % MOD;
        a = 1LL * a * a % MOD;
        b >>= 1;
    }
    return res;
}

int inv(int n) {
    return binpow(n, MOD - 2);
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        int n, m;
        cin >> n >> m;
        cout << (1 - inv(binpow(n, m)) + MOD) % MOD << "\n";
    }
    return 0;
}

B - 牛牛和牛可乐的赌约2

题解

  • $(0,0)$ 为必败态
  • 可以移动到 $(0,0)$ 的 $(0,1),(0,2),(1,0),(2,0)$ 为必胜态
  • 不得不移动到 $(0,1),(0,2),(1,0),(2,0)$ 的 $(3,0),(1,1),(0,3)$ 为必败态
  • …………

以此类推,最终推得规律为 $x\ \%\ 3 = y\ \%\ 3$ 必败。

代码

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        int x, y;
        cin >> x >> y;
        cout << ((x - y) % 3 == 0 ? "awsl" : "yyds") << "\n";
    }
    return 0;
}

C - 单词记忆方法

题解

递归求解每个配对括号内的和,再乘以括号外的倍数即可。

Tips

有可能括号外没有数字,所以 $dfs$ 中的 $mul$ 的初值根据判断条件有两种形式。

代码

#include <bits/stdc++.h>
using namespace std;
constexpr int N = 1e5 + 100;

string s;
int match[N];

void Match() {
    stack<int> stk;
    for (int i = 0; i < s.size(); i++) {
        if (s[i] == '(') {
            stk.push(i);
        } else if (s[i] == ')') {
            int last = stk.top();
            stk.pop();
            match[i] = last;
            match[last] = i;
        }
    }
}

long long dfs(int l, int r) {
    if (l > r) return 0;
    long long res = 0;
    while (l <= r) {
        long long val = 0;
        while (l <= r and isupper(s[l])) {
            val += s[l] - 'A' + 1;
            ++l;
        }
        if (s[l] == '(') {
            val = dfs(l + 1, match[l] - 1);
            l = match[l] + 1;
        }
        long long mul = 1;
        if (l <= r and isdigit(s[l])) {
            mul = 0;
            while (l <= r and isdigit(s[l])) {
                mul = mul * 10 + s[l] - '0';
                ++l;
            }
        }
        res += val * mul;
    }
    return res;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> s;
    Match();
    cout << dfs(0, s.size() - 1) << "\n";
    return 0;
}

D - 位运算之谜

题解

\begin{equation} a + b = x \end{equation}

\begin{equation} a\ \&\ b = y \end{equation}

\begin{equation} a + b = a \oplus b + ((a\ \&\ b) << 1) \end{equation}

将 (1)(2) 代入 (3) 得:

\begin{equation} x = a \oplus b + (y << 1) \nonumber \end{equation}

移项得:

\begin{equation} a \oplus b = x - (y << 1) \nonumber \end{equation}

如果存在整数 $a,b$ 满足条件,那么得到的 $a \oplus b$ 一定满足:

\begin{equation} a \oplus b \ge 0 \nonumber \end{equation}

\begin{equation} (a \oplus b)\ \&\ (a\ \&\ b) = 0 \nonumber \end{equation}

代码

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int t;
    cin >> t;
    while (t--) {
        long long x, y;
        cin >> x >> y;
        long long c = x - (y << 1);
        cout << (c >= 0 and ((c & y) == 0) ? c : -1) << "\n";
    }
    return 0;
}

G - 牛牛和字符串的日常

题解

KMP模板题,稍微改一下求最长前缀即可。(感觉以前哪场比赛好像考过这个)

代码

#include <bits/stdc++.h>
using namespace std;
const int N = 1e6 + 100;

int Next[N];
string s, p;

void init_Next() {
    Next[0] =Next[1] = 0;
    for (int i = 1; i < p.size(); i++) {
        int j = Next[i];
        while (j and p[i] != p[j]) j = Next[j];
        Next[i + 1] = (p[i] == p[j] ? j + 1 : 0);
    }
}

int KMP() {
    int mx = 0;
    int j = 0;
    for (int i = 0; i < s.size(); i++) {
        while (j and s[i] != p[j]) j = Next[j];
        if (s[i] == p[j]) j++;
        mx = max(mx, j);
    }
    return mx;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    long long ans = 0;
    cin >> p;
    init_Next();
    int t; 
    cin >> t;
    while (t--) {
        cin >> s;
        ans += KMP();
    }
    cout << ans << "\n";
    return 0;
}

H - 上学要迟到了

题解

单源最短路模板题。

代码

#include <bits/stdc++.h>
using namespace std;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m, s, t, T;
    cin >> n >> m >> s >> t >> T;
    vector<int> tim(m + 1), a(n + 1);
    for (int i = 1; i <= m; i++)
        cin >> tim[i];
    for (int i = 1; i <= n; i++)
        cin >> a[i];
    vector<vector<pair<int, int>>> G(n + 1);
    for (int u = 1; u + 1 <= n; u++) {
        int v = u + 1;
        G[u].emplace_back(v, T);
        G[v].emplace_back(u, T);
    }
    vector<int> last(m + 1);
    for (int i = 1; i <= n; i++) {
        if (last[a[i]]) {
            int u = last[a[i]];
            int v = i;
            G[u].emplace_back(v, tim[a[i]]);
        }
        last[a[i]] = i;
    }
    function<int(int, int)> Get_distance = [&](int s, int t) {
        vector<int> dis(n + 1, 1e9);
        vector<bool> vis(n + 1);
        priority_queue<pair<int, int>> pque;
        dis[s] = 0;
        pque.emplace(0, s);
        while (!pque.empty()) {
            int u = pque.top().second;
            pque.pop();
            if (vis[u]) continue;
            vis[u] = true;
            for (auto i : G[u]) {
                int v = i.first, w = i.second;
                if (!vis[v] and dis[v] > dis[u] + w) {
                    dis[v] = dis[u] + w;
                    pque.emplace(-dis[v], i.first);
                }
            }
        }
        return dis[t];
    };
    cout << Get_distance(s, t) << "\n";
    return 0;
}

I - 迷宫

题解

计算从 $(1,1)$ 到 $(n,m)$ 的路径数目的状态转移方程为:

\begin{equation} dp_{ij} = dp_{(i-1)j} + dp_{i(j-1)} \nonumber \end{equation}

那么计算模数再加一维状压dp即可。

代码

#include <bits/stdc++.h>
using namespace std;
constexpr int MOD = 1e4 + 7;
int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m;
    cin >> n >> m;
    vector<vector<int>> a(n + 1, vector<int>(m + 1));
    for (int i = 1; i <= n; i++)
        for (int j = 1; j <= m; j++) {
            cin >> a[i][j];
            a[i][j] %= MOD;
        }
    vector<vector<bitset<MOD>>> dp(n + 1, vector<bitset<MOD>>(m + 1));
    dp[1][1].set(a[1][1]);
    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            if (i == 1 and j == 1) continue;
            dp[i][j] |= (dp[i - 1][j] << a[i][j]) | (dp[i - 1][j] >> (MOD - a[i][j]));
            dp[i][j] |= (dp[i][j - 1] << a[i][j]) | (dp[i][j - 1] >> (MOD - a[i][j]));
        }
    }
    cout << dp[n][m].count() << "\n";
    return 0;
}

J - 树上行走

题解

并查集模板题

Tips

一个结点的父亲不一定是 $fa[i]$,应该用 $Find(i)$ 。

代码

#include <bits/stdc++.h>
using namespace std;
constexpr int N = 2e5 + 100;

int fa[N], son_num[N];

int Find(int x) {
    return fa[x] == x ? fa[x] : fa[x] = Find(fa[x]);
}

void Union(int x, int y) {
    x = Find(x);
    y = Find(y);
    if (x != y) {
        fa[y] = x;
        son_num[x] += son_num[y];
    }
}

void Init() {
    for (int i = 0; i < N; i++) {
        fa[i] = i;
        son_num[i] = 1;
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    Init();
    int n;
    cin >> n;
    vector<int> a(n);
    for (int i = 0; i < n; i++)
        cin >> a[i];
    for (int i = 0; i < n - 1; i++) {
        int x, y;
        cin >> x >> y;
        --x, --y;
        if (a[x] == a[y])
            Union(x, y);
    }
    int mx = *max_element(son_num, son_num + n);
    cout << count(son_num, son_num + n, mx) * mx << "\n";
    for (int i = 0; i < n; i++) {
        if (son_num[Find(i)] == mx) {
            cout << i + 1 << ' ';
        }
    }
    return 0;
}

 

posted @ 2020-09-20 23:30  Kanoon  阅读(271)  评论(0编辑  收藏  举报