2020牛客多校第一场

A 后缀数组


我字符串白给,有空补。

F 签到


题意:
给你两个字符串a,b,问你a的无限和b的无限字典序大小关系是什么。
思路:
大胆猜想,设a较长,把a扩大两 (或三)倍,把b补齐,比较一下。

#include <bits/stdc++.h>

using namespace std;

const int maxn = (int)1e6 + 100;
string a, b, aa;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif

    while (cin >> a >> b) {
        bool exchange = false;
        if (int(a.size()) < int(b.size())) {
            swap(a, b);
            exchange = true;
        }
        aa = a;
        aa += a;
        bool big = false;
        bool small = false;
        int temp = int(b.size());
        for (int i = 0; i < int(aa.size()); ++i) {
            if (aa[i] > b[i % int(b.size())]) {
                big = true;
                break;
            }
            if (aa[i] < b[i % int(b.size())]) {
                small = true;
                break;
            }
        }
        if (big) {
            if (exchange) cout << "<" << '\n';
            else cout << ">" << '\n';
        } else if (small) {
            if (exchange) cout << ">" << '\n';
            else cout << "<" << '\n';
        } else {
            cout << "=" << '\n';
        }
    }

#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

H 费用流


题意:
有一个图,a,b,c表示一条流a->b流一个单位就要花费c元,现在有q个询问,问你如果要流u/v的总流到汇点,问你最少要花多少钱。
思路:
最小费用最大流,先乘上v再除以v就行了。

#include <bits/stdc++.h>

using namespace std;

#define ll long long
const int maxn = 200;      //点数
const int INF = 0x3f3f3f3f;
struct Edge{
    int from, to, cap, flow, cost;
    Edge(int u, int v, int c, int f, int cc)
        : from(u), to(v), cap(c), flow(f), cost(cc) {}
};
struct MCMF {
    int n, m;
    vector<Edge> edges;
    vector<int> G[maxn];
    vector< pair<ll, ll> > temp;
    int inq[maxn];  //是否在队列中
    int d[maxn];    //bellmanford
    int p[maxn];    //上一条弧
    int a[maxn];    //可改进量
    void init(int n) {
        this->n = n;
        for (int i = 0; i <= n; ++i) G[i].clear();
        edges.clear();
        temp.clear();  //操操操,忘记初始化
    }
    void addEdge(int from, int to, int cap, int cost) {
        edges.emplace_back(Edge(from, to, cap, 0, cost));
        edges.emplace_back(Edge(to, from, 0, 0, -cost));
        m = int(edges.size());
        G[from].emplace_back(m - 2);
        G[to].emplace_back(m - 1);
    }
    bool spfa(int s, int t, int &flow, ll &cost) {
        for (int i = 1; i <= n; ++i) d[i] = INF;
        memset(inq, 0, sizeof(inq));
        d[s] = 0;
        inq[s] = 1;
        p[s] = 0;
        queue<int> q;
        a[s] = INF;
        q.push(s);
        while (!q.empty()) {
            int u = q.front();
            q.pop();
            inq[u] = 0;
            for (int i = 0; i < int(G[u].size()); ++i) {
                Edge &e = edges[G[u][i]];
                if (e.cap > e.flow && d[e.to] > d[u] + e.cost) {
                    d[e.to] = d[u] + e.cost;
                    p[e.to] = G[u][i];
                    a[e.to] = min(a[u], e.cap - e.flow);
                    if (!inq[e.to]) {
                        q.push(e.to);
                        inq[e.to] = 1;
                    }
                }
            }
        }
		//if (d[t] > k) return false;    //如果费用大于k就退出
		//if (d[t] >= 0) return false;   //最小费用流
        if (d[t] == INF) return false;
        flow += a[t];
        cost += (ll)d[t] * (ll)a[t];
        temp.emplace_back(make_pair(a[t], d[t]));
        for (int u = t; u != s; u = edges[p[u]].from) {
            edges[p[u]].flow += a[t];
            edges[p[u] ^ 1].flow -= a[t];
        }
        return true;
    }
    int MincostMaxflow(int s, int t, ll &cost) {
        int flow = 0;
        cost = 0;
        while (spfa(s, t, flow, cost));
        return flow;
    }
}mcmf;
int n, m, s, t;
bool cmp(pair<ll, ll> a, pair<ll, ll> b) {
    return a.second < b.second;
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif

    while (cin >> n >> m) {
        mcmf.init(n + 10);
        for (int i = 0; i < m; ++i) {
            int u, v, f;
            cin >> u >> v >> f;
            mcmf.addEdge(u, v, 1, f);
        }
        ll cost = 0;
        ll mf = mcmf.MincostMaxflow(1, n, cost);
     //   sort(mcmf.temp.begin(), mcmf.temp.end(), cmp);
        int q;
        cin >> q;
        while (q--) {
            ll u, v;
            cin >> u >> v;
            ll l = 0, r = v;
            if (mf * u  < v) {
                cout << "NaN" << '\n';
                continue;
            }
            ll sum = 0;
            for (pair<int, int> now : mcmf.temp) {
                if (sum + u * now.first <= v) {
                    sum += u * now.first;
                    l += now.first * now.second * u;
                } else {
                    l += (v - sum) * now.second;
                    break;
                }
            }
            ll tm = __gcd(l, r);
            l /= tm; r /= tm;
            cout << l << '/' << r << '\n';
        }
    }

#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

I 一般图最大匹配


1 or 2
题意:
有一个m条边n个点的无向有环图,给你一个数组di表示第i个顶点的出度是d[i],现在让你删某些边,然后满足这个数组d。
思路:
一般图最大匹配,拆顶点表示度数,拆边连顶点。
最后看是不是所有点都能连到,也就是看连的边数*2是不是等于所有的点数就行。

#include <bits/stdc++.h>

using namespace std;

const int maxn = 1100;
int n, m, x, y, tot, d[maxn], sum;
vector<int> G[maxn];
namespace Blossom {
    int mate[maxn], n, ret, nxt[maxn], f[maxn], mark[maxn], vis[maxn], t;
    queue<int> q;
    int F(int x) {return x == f[x] ? x : f[x] = F(f[x]);}
    void Merge(int a, int b) {f[F(a)] = F(b);}
    int lca(int x, int y) {
        for (t++;;swap(x, y)) {
            if (~x) {
                if (vis[x = F(x)] == t) return x;
                vis[x] = t;
                x = (mate[x] != -1 ? nxt[mate[x]] : -1);
            }
        }
    }
    void group(int a, int p) {
        for (int b, c; a != p; Merge(a, b), Merge(b, c), a = c) {
            b = mate[a], c = nxt[b];
            if (F(c) != p) nxt[c] = b;
            if (mark[b] == 2) mark[b] = 1, q.push(b);
            if (mark[c] == 2) mark[c] = 1, q.push(c);
        }
    }
    void aug(int s, const vector<int> G[]) {
        for (int i = 0; i < n; ++i) {
            nxt[i] = vis[i] = -1;
            f[i] = i;
            mark[i] = 0;
        }
        while (!q.empty()) q.pop();
        q.push(s);
        mark[s] = 1;
        while (mate[s] == -1 && !q.empty()) {
            int x = q.front();
            q.pop();
            for (int i = 0, y; i < int(G[x].size()); ++i) {
                if ((y = G[x][i]) != mate[x] && F(x) != F(y) && mark[y] != 2) {
                    if (mark[y] == 1) {
                        int p = lca(x, y);
                        if (F(x) != p) nxt[x] = y;
                        if (F(y) != p) nxt[y] = x;
                        group(x, p); group(y, p);
                    } else if (mate[y] == -1) {
                        nxt[y] = x;
                        for (int j = y, k, l; ~j; j = l) {
                            k = nxt[j];
                            l = mate[k];
                            mate[j] = k;
                            mate[k] = j;
                        }
                        break;
                    } else {
                        nxt[y] = x;
                        q.push(mate[y]);
                        mark[mate[y]] = 1;
                        mark[y] = 2;
                    }
                }
            }
        }
    }
    void solve(int _n, vector<int> G[]) {
        n = _n;
        memset(mate, -1, sizeof(mate));
        for (int i = t =0 ; i < n; ++i) if (mate[i] == -1) aug(i, G);
        for (int i = ret = 0; i < n; ++i) ret += (mate[i] > i);
        if (ret * 2 == sum) {
            cout << "Yes" << '\n';
        } else {
            cout << "No" << '\n';
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(0);
    cout.precision(10);
    cout << fixed;
#ifdef LOCAL_DEFINE
    freopen("input.txt", "r", stdin);
#endif

    while (cin >> n >> m) {
        tot = 2 * n;
        for (int i = 0; i <= 1000; ++i) G[i].clear();
        sum = 2 * m;
        for (int i = 1; i <= n; ++i) {
            cin >> d[i];
            sum += d[i];
        }
        for (int i = 0; i < m; ++i) {
            int u, v;
            cin >> u >> v;
            --u; --v;
            int a1 = tot++, a2 = tot++;
            G[a1].emplace_back(a2);
            G[a2].emplace_back(a1);
            G[u].emplace_back(a1);
            G[a1].emplace_back(u);
            if (d[u + 1] == 2) {
                G[u + n].emplace_back(a1);
                G[a1].emplace_back(u + n);
            }
            G[v].emplace_back(a2);
            G[a2].emplace_back(v);
            if (d[v + 1] == 2) {
                G[v + n].emplace_back(a2);
                G[a2].emplace_back(v + n);
            }
        }
        Blossom::solve(1000, G);
    }

#ifdef LOCAL_DEFINE
    cerr << "Time elapsed: " << 1.0 * clock() / CLOCKS_PER_SEC << " s.\n";
#endif
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值