2018 Multi-University Training Contest 2

2018 Multi-University Training Contest 2

HDU6311 Cover(欧拉路)

The North can be regard as a undirected graph (not necessary to be connected), one soldier can cover one path. Today there’s no so many people still breathing in the north, so the King wants to minimize the number of soldiers he sent to cover each edge exactly once. As a master of his, you should tell him how to arrange soldiers.

题意:给定一个无向图(不一定连通),问至少需要多少条欧拉路径路(一笔画,包括回路)才能覆盖所有的边。

欧拉路的变形
对于一个联通快

  1. 当奇数点 == 0 是欧拉回路,可以一笔走完
  2. 当奇数点 == 2 是欧拉路径,可以一笔走完
  3. 当奇数点 > 2 则至少有k/2条欧拉路

所以DFS所有边就可以找到有多少条欧拉路
另一个问题是输出路径
将奇数点与奇数点之间用虚边相连,这样图就变成了欧拉回路,遍历遇到虚边说明这是一跳欧拉路

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
using namespace std;

const int maxn = 1e5 + 100;
int n, m, sum;
struct edge {
    int u, v, w;
    bool f;
    int next;
} e[maxn * 4];
bool vis[maxn];
int head[maxn], tot = 0, dis[maxn];
vector<int> q[maxn];

void add(int u, int v, int w)
{
    e[tot] = (edge){ u, v, w, false, head[u] };
    head[u] = tot++;
}

void dfs(int x)
{
    vis[x] = true;
    for (int i = head[x]; i != -1; i = e[i].next) {
        int v = e[i].v;
        if (!e[i].f) {
            e[i].f = true;
            e[i ^ 1].f = true;
            dfs(v);
            if (e[i].w)
                q[sum].push_back(e[i].w);
            else {
                //cout << e[i].w << endl;
                sum++;
            }
        }
    }
}

void init()
{
    memset(vis, 0, sizeof(vis));
    tot = 0, sum = 0;
    memset(head, -1, sizeof(head));
    memset(dis, 0, sizeof(dis));
}

int main()
{
    while (~scanf("%d%d", &n, &m)) {
        init();
        for (int i = 1; i <= m; i++) {
            int u, v;
            scanf("%d%d", &u, &v);
            add(u, v, -i);
            add(v, u, i);
            dis[u]++;
            dis[v]++;
        }
        int un = 0;
        for (int i = 1; i <= n; i++) {
            if (dis[i] & 1) {
                if (un == 0)
                    un = i;
                else {
                    add(un, i, 0);
                    add(i, un, 0);
                    un = 0;
                }
            }
        }
        for (int i = 1; i <= n; i++) {
            if (!vis[i] && dis[i] & 1) {
                dfs(i);
            }
        }
        for (int i = 1; i <= n; i++) {
            if (!vis[i] && dis[i]) {

                dfs(i);
                sum++;
            }
        }
        printf("%d\n", sum);
        for (int i = 0; i < sum; i++) {
            printf("%d", q[i].size());
            for (int j = 0; j < q[i].size(); j++) {
                printf(" %d", q[i][j]);
            }
            printf("\n");
            q[i].clear();
        }
    }
    return 0;
}

HDU6312 Game(简单博弈)

Alice and Bob are playing a game.
The game is played on a set of positive integers from 1 to n.
In one step, the player can choose a positive integer from the set, and erase all of its divisors from the set. If a divisor doesn’t exist it will be ignored.
Alice and Bob choose in turn, the one who cannot choose (current set is empty) loses.
Alice goes first, she wanna know whether she can win. Please judge by outputing ‘Yes’ or ‘No’.

题意:给你1-n的数列,每次取一个是并去除它的所有因子

[2-n]为必胜状态,所有谁先手就必会赢,先手把1去除,必胜

#include <iostream>
#include <stdio.h>
using namespace std;

int main()
{
    int n;
    while (~scanf("%d", &n)) {
        cout << "Yes" << endl;
    }
    return 0;
}

HDU6315 Naive Operations(线段树)

In a galaxy far, far away, there are two integer sequence a and b of length n.
b is a static permutation of 1 to n. Initially a is filled with zeroes.
There are two kind of operations:

  1. add l r: add one for al,al+1…ar
  2. query l r: query ∑ri=l⌊ai/bi⌋

待补

HDU6318 Swaps and Inversions(逆序对)

Long long ago, there was an integer sequence a.
Tonyfang think this sequence is messy, so he will count the number of inversions in this sequence. Because he is angry, you will have to pay x yuan for every inversion in the sequence.
You don’t want to pay too much, so you can try to play some tricks before he sees this sequence. You can pay y yuan to swap any two adjacent elements.
What is the minimum amount of money you need to spend?
The definition of inversion in this problem is pair (i,j) which 1≤i<j≤n and ai>aj.

题意:给你一个数列,有1个逆序对就花费x元,交换一组相邻的数花费y元,求花费的min

对于逆序对交换一次相当于消除一个逆序对,所有答案就是n(逆序对数目) * min(x,y)
求逆序对有归并排序和树状数组两种方法

#include <cstdio>
#include <iostream>
using namespace std;
#define ll long long

const int maxn = 1e5 + 100;
int n, x, y;
int a[maxn], val[maxn];
ll sum = 0;

void qsort(int l, int r)
{
    if (l == r)
        return;
    int mid = (l + r) >> 1;
    qsort(l, mid);
    qsort(mid + 1, r);
    int i = l, j = mid + 1, k = l;
    while (i <= mid && j <= r) {
        if (a[i] <= a[j])
            val[k++] = a[i++];
        else
            val[k++] = a[j++], sum += (ll)(mid - i + 1);
    }
    while (i <= mid)
        val[k++] = a[i++];
    while (j <= r)
        val[k++] = a[j++];
    for (int i = l; i <= r; i++)
        a[i] = val[i];
}

int main()
{
    while (~scanf("%d%d%d", &n, &x, &y)) {
        sum = 0;
        for (int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        qsort(1, n);
        ll p = sum * (ll)min(x, y);
        printf("%lld\n", p);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值