2020 Multi-University Training Contest 2

Contents

概要

01 02 03 04 05 06 07 08 09 10 11 12
总体 ? ? ? ?
wzgy ?
csz ? ?
wh ?

比赛地址

2020 Multi-University Training Contest 2

题目

1005. New Equipments

题目大意:

给出 n 个工人和 m 台机器,第 i 个工人和第 j 台机器匹配的代价是 a[ i ] \cdot j^2 + b[ i ] \cdot j + c[ i ] ,问如何进行匹配,可以使得代价和最小。要求分别输出匹配 1n 个工人的最小代价。

解题思路:

代价可以视为二次函数,且数据范围限制了系数 a 是大于 0 的,即二次函数的开口向上,这样函数就存在着最小值。

考虑 n 最大只有 50 ,所以我们可以对于每个工人的二次函数,求出与其匹配所花费代价的前 n 小的位置(方法:找出二次函数对称轴,往左往右分别找 n 个点,排序后取最小的 n 个点),直接将工人与机器连边求解即可。注意到零件的编号可能会很大,需要进行离散化处理。因为每个工人都与 n 个机器建边,所以最终一定可以达到完全匹配,最终有 n 个工人,至多 n^2 台机器,使用 spfa 的费用流即可通过。

对于题目要求的输出,即求匹配数为 1n 的最小费用,我们可以在源点之前再建立一个超级源点,每次向源点连一条容量为 1、费用为 0 的边,在参与网络上继续跑费用流即可。

AC代码:

#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const long long INF = 1e18;
const int N = 5e3 + 50;
const int MAXM = 6e5 + 50;

int head[N], tot = 1;
struct Edge
{
    int nex, to, w;
    long long c;
}e[2 * MAXM];
void addedge(int a, int b, int c, long long d)
{
    e[++tot] = (Edge) {head[a], b, c, d};
    head[a] = tot;
}
void add(int a, int b, int c, long long d) {
    addedge(a, b, c, d);
    addedge(b, a, 0, -d);
}

struct MCMF {
    queue<int> q;
    int n, S, T;
    long long maxflow, mincost;
    int pre[N], last[N], vis[N], flow[N];
    long long dis[N];

    void init(int _n, int _S, int _T) {
        n = _n; S = _S; T = _T;
        maxflow = mincost = 0;
        memset(head, 0, sizeof(head));
        tot = 1;
    }
    int spfa() {
        for (int i = 1; i <= n; i++) {
            dis[i] = INF; vis[i] = 0;
        }
        dis[S] = 0; vis[S] = 1;
        flow[S] = 1e9; pre[T] = 0;
        while(!q.empty()) q.pop(); q.push(S);
        while(!q.empty())
        {
            int now = q.front();
            q.pop(); vis[now] = 0;
            for(int i = head[now]; i; i = e[i].nex)
            {
                int to = e[i].to;
                if(e[i].w && dis[to] > dis[now] + e[i].c)
                {
                    dis[to] = dis[now] + e[i].c;
                    pre[to] = now;
                    last[to] = i;
                    flow[to] = min(e[i].w, flow[now]);
                    if(!vis[to])
                    {
                        vis[to] = 1;
                        q.push(to);
                    }
                }
            }
        }
        return pre[T] > 0;
    }

    void solve() {
        while(spfa()) {
            maxflow += flow[T];
            mincost += 1LL * flow[T] * dis[T];
            for(int now = T; now != S; now = pre[now])
            {
                e[last[now]].w -= flow[T];
                e[last[now]^1].w += flow[T];
            }
        }
    }
}mcmf;

int n, m;
long long a[55], b[55], c[55];

__int128 f(int i, int j) {
    return (__int128)a[i] * j * j + b[i] * j + c[i];
}

struct Node {
    int i, j;
    bool operator < (const Node &x) const {
        return f(i, j) < f(x.i, x.j);
    }
};

vector<Node> v[55];
vector<int> all;

void discreate(vector<int> &v) {
    sort(v.begin(), v.end());
    v.erase(unique(v.begin(), v.end()), v.end());
}

int id(int j, vector<int> &v = all) {
    return (int)(lower_bound(v.begin(), v.end(), j) - v.begin()) + 1;
}

void solve() {
    int SS = mcmf.S, S = SS - 2;
    for (int i = 1; i <= n; i++) {
        add(SS, S, 1, 0);
        mcmf.solve();
        printf("%lld%c", mcmf.mincost, i == n ? '\n' : ' ');
    }
}

int main()
{
    int ; scanf("%d", &);
    while ($--) {
        scanf("%d%d", &n, &m);
        all.resize(0);
        for (int i = 1; i <= n; i++) {
            v[i].resize(0);
            scanf("%lld %lld %lld", &a[i], &b[i], &c[i]);
            int pos = (int)(-b[i] / (2 * a[i]));
            pos = min(pos, m);
            pos = max(pos, 1);
            for (int j = pos, cnt = 0; j <= m && cnt <= n; j++, cnt++) {
                v[i].push_back((Node){i, j});
            }
            for (int j = pos - 1, cnt = 0; j > 0 && cnt <= n; j--, cnt++) {
                v[i].push_back((Node){i, j});
            }
            sort(v[i].begin(), v[i].end());
            v[i].resize(n);
            for (Node x : v[i]) {
                all.push_back(x.j);
            }
        }
        discreate(all);
        int S = n + (int)all.size() + 1, T = S + 1, SS = T + 1;
        mcmf.init(SS, SS, T);
        for (int i = 1, sz = (int)all.size(); i <= sz; i++) {
            add(n + i, T, 1, 0);
        }
        for (int i = 1; i <= n; i++) {
            add(S, i, 1, 0);
            for (Node x : v[i]) {
                long long cost = (long long)f(i, x.j);
                int to = id(x.j) + n;
                add(i, to, 1, cost);
            }
        }
        solve();
    }
    return 0;
}

1006. The Oculus

题目大意:

定义 F_i 为斐波那契数列第 i 项,F_1=1,F_2=2,F_i=F_{i-1}+F_{i-2}(i≥3)

已知任意正整数 x 都拥有一个唯一的长度为 n01 数列 b,使得

b_1\cdot F_1+b_2\cdot F_2+…+b_n\cdot F_n=x

b_n=1;\ b_i= 0\ or\ 1;\ b_i\cdot b_{i+1}=0

以这样的表示法给出 A、B、C 三个数

已知数字 C 是由 A\cdot B 的结果在这样的表示法下将某个原本是 1 的位置改成 0 得来的,问抹去的是哪个位置。

解题思路:

使用双模数哈希,预处理出斐波那契数列的前 N 项分别对 10^9+710^9+9 取模。将 (f[i],i) 作为一个 pair 放入 vector 中并排好序。

利用预处理,我们可以很方便地得到 A,B,C 代表的数对 10^9+710^9+9 取模后得到的值 x,y,z。则被除去的数应当等于 ans=x\times y-z。遍历两个 vector 中所有满足条件的 pair(f[i]=ans),如果它们的 i 相同则为答案。

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int P1 = 1e9 + 7;
const int P2 = 1e9 + 9;
const int N = 1e6 + 50;
int f1[N + N], f2[N + N];
vector< pair<int, int> > ma1, ma2;

void init() {
    f1[1] = f2[1] = 1;
    ma1.push_back(make_pair(1, 1));
    ma2.push_back(make_pair(1, 1));
    f1[2] = f2[2] = 2;
    ma1.push_back(make_pair(2, 2));
    ma2.push_back(make_pair(2, 2));
    int cnt = 0;
    for (int i = 3; i < N + 1e6; i++) {
        f1[i] = (f1[i - 1] + f1[i - 2]) % P1;
        f2[i] = (f2[i - 1] + f2[i - 2]) % P2;
        ma1.push_back(make_pair(f1[i], i));
        ma2.push_back(make_pair(f2[i], i));
    }
    sort(ma1.begin(), ma1.end());
    sort(ma2.begin(), ma2.end());
}

int main()
{
    init();
    int T; scanf("%d", &T);
    while (T--) {
        int a, b, c;
        int x1 = 0, y1 = 0, z1 = 0;
        int x2 = 0, y2 = 0, z2 = 0;
        scanf("%d", &a);
        for (int i = 1, ; i <= a; i++) {
            scanf("%d", &);
            (x1 += * f1[i]) %= P1;
            (x2 += * f2[i]) %= P2;
        }
        //printf("#%d %d\n", x1, x2);
        scanf("%d", &b);
        for (int i = 1, ; i <= b; i++) {
            scanf("%d", &);
            (y1 += * f1[i]) %= P1;
            (y2 += * f2[i]) %= P2;
        }
        //printf("#%d %d\n", y1, y2);
        scanf("%d", &c);
        for (int i = 1, ; i <= c; i++) {
            scanf("%d", &);
            (z1 += * f1[i]) %= P1;
            (z2 += * f2[i]) %= P2;
        }
        int d1 = (1LL * x1 * y1 % P1 - z1 + P1) % P1;
        int d2 = (1LL * x2 * y2 % P2 - z2 + P2) % P2;
        //printf("#%d %d\n", d1, d2);
        int a1 = lower_bound(ma1.begin(), ma1.end(), make_pair(d1, -1)) - ma1.begin();
        int a2 = upper_bound(ma1.begin(), ma1.end(), make_pair(d1, P1)) - ma1.begin();
        int b1 = lower_bound(ma2.begin(), ma2.end(), make_pair(d2, -1)) - ma2.begin();
        int b2 = upper_bound(ma2.begin(), ma2.end(), make_pair(d2, P2)) - ma2.begin();
        for (int cnt1 = a1; cnt1 < a2; ++cnt1) {
            int flag = 0;
            int ans1 = ma1[cnt1].second;
            for (int cnt2 = b1; cnt2 < b2; ++cnt2) {
                int ans2 = ma2[cnt2].second;
                if (ans1 == ans2) {
                    printf("%d\n", ans1);
                    flag = 1;
                    break;
                }
            }
            if (flag) {
                break;
            }
        }
    }
    return 0;
}
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇