2021年ACM竞赛班训练(十一)

Posted lhqwd

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了2021年ACM竞赛班训练(十一)相关的知识,希望对你有一定的参考价值。

B题 奖学金

算法一: 拓扑排序

思路:

对于任给的一个意见(\\(a\\)同学比\\(b\\)同学高)转化为: 存在一条由\\(a\\)\\(b\\)的权重为\\(1\\)的有向边
构建一个图, 经过拓扑排序, 保证图中每一个点在其前驱点入队前不会入队.
对应本题就是:保证每一个同学能够满足所有的不等式。

#include <iostream>
#include <cstring>
#include <queue>
#include <string>

using namespace std;

const int N = 1e5 + 10;
const int M = 2 * N;

int h[N], e[M], ne[M], idx, w[M];

int dist[N];
int din[N];

void add(int a, int b, int v)
{
    e[idx] = b, ne[idx] = h[a], w[idx] = v, h[a] = idx++;
}

int main()
{
    int n, m;
    cin >> n >> m;
    memset (h, -1, sizeof h);
    queue<int> q;


    for (int i = 1; i <= m; i ++ ){
        int a, b;
        cin >> a >> b;
        add(b, a, 1);
        din[a]++;
    }

    for (int i = 1; i <= n; i ++ )
        if (!din[i]){
            q.push(i);
        }
    
    while (q.size()){
        int u = q.front();
        q.pop();

        for (int i = h[u]; i != -1; i = ne[i]){
            int j = e[i];

            if (dist[j] <= dist[u] + w[i])
                dist[j] = dist[u] + w[i];

            din[j]--;

            if (!din[j])
                q.push(j);
        }
    }

    long long ans = 100 * n;

    for (int i = 1; i <= n; i ++ )
        if (din[i]){
            puts("impossible");
            return 0;
        }else
            ans += dist[i];

    cout << ans << endl;

    return 0;
}

算法二: 差分约束

思路:

问题转化为不等式: \\(a > b + 1\\)
对于每一个不等式, 构建一条\\(b\\)\\(a\\)的边, 再构建一个到所有点的虚拟原点.
问题要求最小值, 用\\(spfa\\)求最长路.

注意: 需要用\\(spfa\\)判环(该题是判正环), 使用队列可能TLE(本题使用队列被卡), 可将队列换成栈.

#include <iostream>
#include <cstring>
#include <queue>
#include <algorithm>
#include <queue>
#include <stack>

using namespace std;

const int N = 2e5 + 10;
const int M = 2 * N;

int dist[N];
int cnt[N];
int h[N], e[M], ne[M], w[M], idx;
int st[N];

int n, m;

void add(int a, int b, int v)
{
    e[idx] = b, w[idx] = v, ne[idx] = h[a], h[a] = idx++;
}


int spfa()
{
    memset(dist, -1, sizeof dist);
    dist[0] = 0;
    stack<int> q;
    q.push(0);
    st[0] = 1;

    while (q.size()){
        int u = q.top();
        q.pop();
        st[u] = 0;

        for (int i = h[u]; i != -1; i = ne[i]){
            int j = e[i];

            if (dist[j] < dist[u] + w[i]){
                dist[j] = dist[u] + w[i];
                cnt[j] += 1;
                if (cnt[j] > n + 1)
                    return 1;
                if (!st[j]){
                    q.push(j);
                    st[j] = 1;
                }
            }

        }
    }
    return 0;
}

int main()
{
    cin >> n >> m;
    memset(h, -1, sizeof h);

    for (int i = 1; i <= m; i ++ ){
        int a, b;
        scanf("%d%d", &a, &b);
        add(b, a, 1);

    }

    for (int i = 1; i <= n; i ++ )
        add(0, i, 0);

    if (spfa())
        puts("impossible");
    else{

        long long ans = 0;
        for (int i = 1; i <= n; i ++ )
            ans += dist[i];
        ans += 100 * n;
        cout << ans << endl;
    }

    return 0;
}

C题 zzh找数字

思路:

暴力模拟即可, 注意特判为\\(0\\)的情况

#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

int num[11];

void solve()
{
    int ans = 0;
    int a, b;
    scanf("%d%d", &a, &b);
    for (int i = 0; i <= 10; i ++ )
        num[i] = 0;
    
    if (a == 0 || b == 0){
        num[0] = 1;
    }

    while (a){
        num[a % 10] = 1;
        a = a / 10;
    }
    while (b){
        num[b % 10] = 1;
        b = b / 10;
    }

    for (int i = 0; i <= 1000; i ++ ){
        int t = i;
        int flag = 1;
        if (t == 0){
            if (num[0] == 0)
                ans += 1;
        }
        while (t){
            if (num[t % 10]){
                flag = 0;
                break;
            }
            t = t / 10;
        }
        if (flag)
            ans += 1;
    }

    cout << ans - 1 << endl;
}

int main()
{
    int t;
    scanf("%d", &t);
    while (t -- )
        solve();

    return 0;
}

E题 调皮的摩尔

原题链接

算法: 字符串哈希

将一个字符串转化为整数存储,同时保证字符串不同,产生的数字不同。

注意点:

1. unsigned long long

unsigned long long (\\(2^{64} - 1\\)), 溢出自动取模

2. 哈希值的计算方法

已知字符串\\(S\\), 根据\\(hash[r]\\)\\(hash[l]\\) 计算子串\\(l-r\\)的哈希值:
\\(hash[l - r] = hash[r] - hash[l] * p^{r -l + 1}\\)

代码

#include <iostream>
#include <cstring>

using namespace std;

int main()
{
    unsigned long long ans = 0;

    string s;
    cin >> s;
    unsigned long long base = 1;
    for (int i = s.size() - 1; i >= 0; i -- ){
        if (s[i] >= \'a\' && s[i] <= \'z\')
            ans = ans + base * (unsigned long long)(s[i] - \'a\');
        else{
            ans = ans + base * (unsigned long long)(s[i] - \'A\');
        }
        base = base * 26;
    }

    cout << ans << endl;

    return 0;
}

以上是关于2021年ACM竞赛班训练(十一)的主要内容,如果未能解决你的问题,请参考以下文章

2021年ACM竞赛班训练 E题 调皮的摩尔

buctoj2021年ACM竞赛班训练题解

2021年ACM竞赛班训练2021.5.21-问题 A: 尝试看到这道题吧-题解

高精度加法讲解-And-2021年ACM竞赛班训练2021.5.13-问题 F: 最遥远的距离-题解

集合划分讲解-And-2021年ACM竞赛班训练2021.5.20-问题 E: 登上火星-题解

高精度加法讲解-And-2021年ACM竞赛班训练2021.5.13-问题 E: Python大法好-题解