7.12 2020牛客暑期多校训练营(第一场)题解及补题

7.12 2020牛客暑期多校训练营(第一场)题解及补题

比赛过程

最先开的F题,一开始我们想的是重复长度到两个字符串的最小公倍数,但是忽略了时间复杂度T了一发,幸好没一会就想到了正解。然后就去看J题了,J题找规律找了很久。

题解

F Infinite String Comparision

题目链接

题意

给你两个字符串,比较这两个字符串各自重复无限次以后的字典序。

解法

将两个字符串重复到这两个字符串长度中较大的那个的两倍的长度,就可以比较了。在重复过程中若字符不相等可直接比较出答案。

代码

#include <bits/stdc++.h>
#define IO ios::sync_with_stdio(0), cin.tie(0)
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const int inf = ~0u >> 1;
typedef pair<int,int> P;
#define REP(i, a, n) for (int i = a; i < (n); ++i)
#define PER(i, a, n) for (int i = (n) - 1; i >= a; --i)
int main() {
    IO;
    string a, b;
    while (cin >> a >> b) {
        if (a == b) {
            cout << "=" << endl;
        }
        else {
            string aa, bb;
            int la = a.length(), lb = b.length();
            int cnt = max(la,lb)*2;
            bool flag=true;
            REP(i, 0, cnt) {
                if(a[i % la]>b[i % lb]) {
                    cout << ">" << endl;
                    flag=false;
                    break;
                }
                else if(a[i % la]<b[i % lb]) {
                    cout << "<" << endl;
                    flag=false;
                    break;
                }
            }
            if (flag==true)
            {
                cout << "=" << endl;
            }
             
        }
    }
     
    return 0;
}

J Easy Integration

题目链接

题意

给你n,\(\int_0^1(x - x^2)^n = \frac {p}{q}\),输出 \((p * q^{-1})\ mod\ 998244353\)

解法

找规律,答案就是\(\frac{(n!)^2}{(2n + 1)!}\),再利费马小定理求逆元即可

代码

#include <bits/stdc++.h>
#define IO ios::sync_with_stdio(0), cin.tie(0)
using namespace std;
typedef long long ll;
const int maxn = 1e6 + 5;
const int inf = ~0u >> 1;
typedef pair<int,int> P;
#define REP(i, a, n) for (int i = a; i < (n); ++i)
#define PER(i, a, n) for (int i = (n) - 1; i >= a; --i)
const ll mod = 998244353;
ll b[2 * maxn], c[maxn];
ll qpowmod(ll a, ll b, ll p){
    a %= p;
    ll ans = 1,base = a;
    while(b != 0){
        if(b & 1)
            ans = ans *  base % p;
        base = base *  base % p;
        b >>= 1;
    }
    return ans;
}
ll getinv(ll a) {
    return qpowmod(a, mod - 2, mod);
}
 
int main() {
    IO;
    ll n;
    b[0] = 1;
    REP(i, 1, 2 * maxn + 1) {
        b[i] = b[i - 1] * i % mod;
    }
    //cout << b[2 * (ll)1e6 + 1] << endl;
    while (cin >> n) {
        ll fenmu = (b[2 * n + 1] % mod * getinv(qpowmod(b[n], 2, mod))) % mod;
        //cout << fenmu << endl;
        ll ans = (1ll * getinv(fenmu)) % mod;
        cout << ans << endl;
    }
     
    return 0;
}

I 1 or 2

题目链接

题意

给你n个点m条边组成的图,问你能不能选择其中的一些边使得点\(\,a_i\,\)的度等于\(\,d_i\,\)

解法

分两种情况:

  1. 因为选择一条边的话将会有两个点的度+1,所以如果\(\,\sum d_i\,\)等于奇数则直接输出No
  2. 建立一个源点和一个汇点,对每个点\(\,a_i\,\)建立一条从源点到\(\,a_i\,\)的边,权值为\(\,d_i\,\),再将点\(\,a_i\,\)复制,建立一条从复制的\(\,a_i'\,\)到汇点的边,权值也为\(\,d_i\,\)。对于相连的两个点\(\,a_i\,\),\(\,a_j\,\),建立一条从\(\,a_i\,\)\(\,a_j'\,\)的权值为1的边,再建立一条从\(\,a_j\,\)\(\,a_i'\,\)的权值为1的边。然后跑一遍最大流,如果最大流等于\(\,\sum d_i\,\)则输出Yes,否则No

代码

#include <bits/stdc++.h>
#define IO ios::sync_with_stdio(0), cin.tie(0)
using namespace std;
typedef long long ll;
const int maxn = 1e5 + 5;
const int inf = ~0u >> 1;
typedef pair<int, int> P;
#define REP(i, a, n) for (int i = a; i < (n); ++i)
#define PER(i, a, n) for (int i = (n)-1; i >= a; --i)
 
struct E {
    int from, to, cap, flow;
    E() {}
    E(int f, int t, int c, int fl) : from(f), to(t), cap(c), flow(fl) {}
};
 
struct Dinic {
    int n, m, s, t;
    vector<E> e;
    vector<int> G[maxn];
    bool vis[maxn];
    int cur[maxn];
    int d[maxn];
    const int INF = 1 << 29;
    void init(int n, int s, int t) {
        this->n = n, this->s = s, this->t = t;
        e.clear();
        for (int i = 0; i < n; ++i) G[i].clear();
    }
 
    void add(int from, int to, int cap) {
        e.push_back(E(from, to, cap, 0));
        e.push_back(E(to, from, 0, 0));
        m = e.size();
        G[from].push_back(m - 2);
        G[to].push_back(m - 1);
    }
 
    bool bfs() {
        queue<int> Q;
        memset(vis, 0, sizeof(vis));
        vis[s] = true;
        d[s] = 0;
        Q.push(s);
        while (!Q.empty()) {
            int x = Q.front();
            Q.pop();
            for (int i = 0; i < G[x].size(); ++i) {
                E &ed = e[G[x][i]];
                if (!vis[ed.to] && ed.cap > ed.flow) {
                    vis[ed.to] = true;
                    d[ed.to] = d[x] + 1;
                    Q.push(ed.to);
                }
            }
        }
        return vis[t];
    }
 
    int dfs(int x, int a) {
        if (x == t || a == 0) return a;
        int flow = 0, f;
        for (int &i = cur[x]; i < G[x].size(); ++i) {
            E &ed = e[G[x][i]];
            if (d[ed.to] == d[x] + 1 &&
                (f = dfs(ed.to, min(a, ed.cap - ed.flow))) > 0) {
                ed.flow += f;
                e[G[x][i] ^ 1].flow -= f;
                flow += f;
                a -= f;
                if (a == 0) break;
            }
        }
        return flow;
    }
 
    int max_flow() {
        int ans = 0;
        while (bfs()) {
            memset(cur, 0, sizeof(cur));
            ans += dfs(s, INF);
        }
        return ans;
    }
} DC;
int d[55];
int main() {
    IO;
    int n, m;
    while (cin >> n >> m) {
        DC.init(2 * n + 2, 0, n + n + 1);
        int sum = 0;
        REP(i, 1, n + 1) {
            cin >> d[i];
            DC.add(0, i, d[i]);
            DC.add(n + i, n + n + 1, d[i]);
            sum += d[i];
        }
        if (sum % 2) {
            cout << "No" << endl;
            continue;
        }
        while (m--) {
            int a, b;
            cin >> a >> b;
            DC.add(a, b + n, 1);
            DC.add(b, a + n, 1);
        }
        if (DC.max_flow() == sum) {
            cout << "Yes" << endl;
        }
        else
            cout << "No" << endl;
    }
    return 0;
}

H Minimum-cost Flow

题目链接

题意

给定一个流网络 n≤50,m≤100,∑m≤104(n个点,m条边),q(∑q≤106) 次询问,每次给定一个分数 u/v,问所有边的容量是 u/v 时费用流的费用。

解法

首先由于边的流量均为分数(u/v),而总流量为 11 个单位。我们先扩大v/u倍,将每条边的流量固定为 1 个单位,此时流量为 v/u 个单位。在最大流使用 SPFA 查找路径时,当查找到一条路径时,此路径的流量一定为 1 (根据设定)。由于采用的本身便是最短路查找路径,得到的路径的费用为当前网络图下的最低费用。可以稍微修改费用流板子中的一部分代码,使得每次得到路径并结算费用时,将每次得到的路径费用记录下来并保存。

代码

#include <algorithm>
#include <bitset>
#include <cctype>
#include <cerrno>
#include <clocale>
#include <cmath>
#include <complex>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <ctime>
#include <deque>
#include <exception>
#include <fstream>
#include <functional>
#include <limits>
#include <list>
#include <map>
#include <iomanip>
#include <ios>
#include <iosfwd>
#include <iostream>
#include <istream>
#include <ostream>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <stdexcept>
#include <streambuf>
#include <string>
#include <utility>
#include <vector>
#include <cwchar>
#include <cwctype>
#include<unordered_map>
using namespace std;
#define ls rt << 1
#define rs ls | 1
#define Min(x, y) x = min(x, y)
#define Max(x, y) x = max(x, y)
#define ALL(x) (x).begin(),(x).end()
#define SZ(x) ((int)(x).size())
#define pir pair <int, int>
#define MK(x, y) make_pair(x, y)
#define MEM(x, b) memset(x, b, sizeof(x))
#define MPY(x, b) memcpy(x, b, sizeof(x))
#define lowbit(x) ((x) & -(x))
#define P2(x) ((x) * (x))
 
typedef long long ll;
const int Mod = 1e9 + 7;
const int N = 55;
const int M = 210;
const int INF = 0x3f3f3f3f;
const ll LINF = 0x3f3f3f3f3f3f3f3f;
 
struct Edge
{
    ll f, w;
    int v, nxt;
}G[M];
ll dis[N], flow[N];
ll mxflow, mincost;
int n, m, sp, tp;
int h[N], cnt, L, R;
int pre[N], lst[N];
bool vis[N];
map <ll, ll> mp;
 
ll gcd(ll a, ll b) {
    return !b ? a : gcd(b, a % b);
}
void init() {
    for (int i = 1; i <= n; i++)
        h[i] = -1;
    L = 1, R = n, cnt = 0;
    mxflow = mincost = 0;
    mp.clear();
}
void Add(int u, int v, ll f, ll w) {
    G[cnt].v = v, G[cnt].f = f, G[cnt].w = w;
    G[cnt].nxt = h[u], h[u] = cnt++;
 
    G[cnt].v = u, G[cnt].f = 0, G[cnt].w = -w;
    G[cnt].nxt = h[v], h[v] = cnt++;
}
bool Spfa() {   // 找到一条最短路的增广
    queue <int> q;
    for (int i = L; i <= R; i++) {
        dis[i] = flow[i] = LINF;
        vis[i] = false;
    }
    q.push(sp);
    vis[sp] = true;
    dis[sp] = 0, pre[tp] = -1;
 
    while (!q.empty()) {
        int u = q.front();
        q.pop();
        vis[u] = false;
 
        for (int i = h[u]; i != -1; i = G[i].nxt) {
            ll f = G[i].f, w = G[i].w;
            int v = G[i].v;
            if (f && dis[v] > dis[u] + w) {
                dis[v] = dis[u] + w;
                pre[v] = u;
                lst[v] = i;
                flow[v] = min(flow[u], f);
                if (!vis[v]) {
                    vis[v] = true;
                    q.push(v);
                }
            }
        }
    }
    return pre[tp] != -1;
}
void MCFC() {    // 对于当前最短路更新流量
    while (Spfa()) {
        int now = tp;
        mxflow += flow[tp];
        mincost += flow[tp] * dis[tp];
        mp[flow[tp] * dis[tp]] += flow[tp];
 
        while (now != sp) {
            G[lst[now]].f -= flow[tp];
            G[lst[now] ^ 1].f += flow[tp];
            now = pre[now];
        }
    }
}
 
int main()
{
    while (~scanf("%d %d", &n, &m)) {
        sp = 1, tp = n;
        init();
        for (int i = 0; i < m; i++) {
            int u, v, w;
            scanf("%d %d %d", &u, &v, &w);
            Add(u, v, 1, w);
        }
        MCFC();
        int q;
        scanf("%d", &q);
        while (q--) {
            ll u, v;
            scanf("%lld %lld", &u, &v);
            ll x = 0, y = v;
            if (mxflow * u < v)
                puts("NaN");
            else {
                ll x = 0, y = v;      
                // 从小到大删
                for (auto it : mp) {
                    // 加u
                    if (it.second * u < v) {
                        v -= it.second * u;
                        x += it.first / it.second * u;
                    }
                    // 加剩余的v
                    else {
                        x += it.first / it.second * v;
                        break;
                    }
                }
                ll gc = gcd(x, y);
                printf("%lld/%lld\n", x / gc, y / gc);
            }
        }
    }
    return 0;
}
posted @ 2020-07-19 15:20  cugbacm03  阅读(136)  评论(0)    收藏  举报