2020 Multi-University Training Contest 4

Contest Info


传送门

Solved A B C D E F G H I J K L
8 / 12 - O Ø O O - Ø - Ø - O Ø
  • O 在比赛中通过
  • Ø 赛后通过
  • ! 尝试了但是失败了
  • - 没有尝试

Solutions


B. Blow up the Enemy

签到。

Code
// Author : heyuhhh
// Created Time : 2020/07/30 12:48:55
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 1e5 + 5;
const double eps = 1e-7;
void run() {
    int n;
    cin >> n;
    vector<int> a(n), d(n);
    vector<int> t(n);
    for (int i = 0; i < n; i++) {
        cin >> a[i] >> d[i];
        int nd = (100 + a[i] - 1) / a[i];
        t[i] = (nd - 1) * d[i];
    }
    double ans = 0;
    for (int i = 0; i < n; i++) {
        double res = 0;
        for (int j = 0; j < n; j++) {
            if (fabs(t[i] - t[j]) < eps) {
                res += 0.5;
            } else if (t[i] > t[j] + eps) {
            } else {
                res += 1;
            }
        }
        res /= 1.0 * n;
        ans = max(ans, res);
    }
    cout << ans << '\n';
}
int main() {
#ifdef Local
    freopen("input.in", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(10);
    int T; cin >> T; while(T--)
    run();
    return 0;
}

C. Contest of Rope Pulling

直接随机一下,然后一个是正贡献、一个是负贡献,做个背包就行,可以设定一个上限大概为根号级别。应该就可以过了。。

D. Deliver the Cake

跑个带有两个附加状态的最短路就行。

E. Equal Sentences

dp一下。

Code
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef double db;
typedef long double ld;
const int MAXN = 1e5 + 5, MAXM = 4e5 + 5, BOUND = 2e5, MOD = 1e9+7, INF = 0x3f3f3f3f, base = 10000;
const int inv2 = (MOD + 1) >> 1;
const ll INFL = 0x3f3f3f3f3f3f3f3f;
const double PI = acos(-1.0), eps = 1e-9;
#define lson o<<1,l,m
#define rson o<<1|1,m+1,r
#define mid l+((r-l)>>1)
#define lc(x) ch[x][0]
#define pii pair<int,int>
#define vi vector<int>
#define vii vector<pair<int,int>>
#define rc(x) ch[x][1]
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define all(a) (a).begin(), (a).end()
#define sz(a) int(a.size())
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define fi first
#define se second
#define MP std::make_pair
#define ri register int
//#define sz(a) int((a).size())
inline int add(int a, int b) {return a + b >= MOD ? a + b - MOD : a + b;}
inline int dec(int a, int b) {return a < b ? a - b + MOD : a - b;}
inline int mul(int a, int b) {return 1ll * a * b % MOD;}
template <typename T>
inline void cmin(T &a,T b){a = min(a,b);}
template <typename T>
inline void cmax(T &a,T b){a = max(a,b);}
ll qpow(ll a,ll b){
    ll ans=1;
    for(;b;b>>=1,a=a*a%MOD)if(b&1)ans=ans*a%MOD;
    return ans;
}
mt19937 mrand(random_device{}());

string s[MAXN];
int f[MAXN];
void run(){
    int n; cin>>n;
    rep(i,1,n){
        cin>>s[i];
    }
    f[0] = 1;
    rep(i,1,n){
        f[i] = f[i-1];
        if(s[i] != s[i-1])f[i] = add(f[i], f[i-2]);
    }
    cout<<f[n]<<'\n';
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    int _=1;
    cin>>_;
    while(_--)run();
    return 0;
}

G. Go Running

考虑建图,从左往右的情况连边,会有若干条链;从右往左也是。并且链的斜率都为正负1。
那么考虑将这个图旋转一下变为网格图,要求的就是选择最少的行、列来覆盖这个网格图。这就是一个最小点覆盖的问题。
使用dinic跑最大流复杂度为\(O(n\sqrt{n})\),并且上界也比较松。

Code
// Author : heyuhhh
// Created Time : 2020/07/30 14:08:31
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
void err(int x) {cerr << x;}
void err(long long x) {cerr << x;}
void err(double x) {cerr << x;}
void err(char x) {cerr << '"' << x << '"';}
void err(const string &x) {cerr << '"' << x << '"';}
void _print() {cerr << "]\n";}
template<typename T, typename V>
  void err(const pair<T, V> &x) {cerr << '{'; err(x.first); cerr << ','; err(x.second); cerr << '}';}
template<typename T>
  void err(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? "," : ""), err(i); cerr << "}";}
template <typename T, typename... V>
  void _print(T t, V... v) {err(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
#ifdef Local
#define dbg(x...) cerr << "[" << #x << "] = ["; _print(x)
#else
#define dbg(x...)
#endif
const int N = 4e5 + 5;

int n;
template <class T>
struct Dinic{
    struct Edge{
        int v, next;
        T flow;
        Edge(){}
        Edge(int v, int next, T flow) : v(v), next(next), flow(flow) {}
    }e[N << 1];
    int head[N], tot;
    int dep[N];
    void init() {
        memset(head, -1, sizeof(int) * (2 * n + 10)); tot = 0;
    }
    void adde(int u, int v, T w, T rw = 0) {
        e[tot] = Edge(v, head[u], w);
        head[u] = tot++;
        e[tot] = Edge(u, head[v], rw);
        head[v] = tot++;
    }
    bool BFS(int _S, int _T) {
        memset(dep, 0, sizeof(dep));
        queue <int> q; q.push(_S); dep[_S] = 1;
        while(!q.empty()) {
            int u = q.front(); q.pop();
            for(int i = head[u]; ~i; i = e[i].next) {
                int v = e[i].v;
                if(!dep[v] && e[i].flow > 0) {
                    dep[v] = dep[u] + 1;
                    q.push(v);
                }
            }
        }
        return dep[_T] != 0;
    }
    T dfs(int _S, int _T, T a) {
        T flow = 0, f;
        if(_S == _T || a == 0) return a;
        for(int i = head[_S]; ~i; i = e[i].next) {
            int v = e[i].v;
            if(dep[v] != dep[_S] + 1) continue;
            f = dfs(v, _T, min(a, e[i].flow));
            if(f) {
                e[i].flow -= f;
                e[i ^ 1].flow += f;
                flow += f;
                a -= f;
                if(a == 0) break;
            }
        }
        if(!flow) dep[_S] = -1;
        return flow;
    }
    T dinic(int _S, int _T) {
        T max_flow = 0;
        while(BFS(_S, _T)) max_flow += dfs(_S, _T, INF);
        return max_flow;
    }
};

Dinic<int> solver;

void run() {
    cin >> n;
    map<int, vector<int>> lr, rl;  
    for (int i = 0; i < n; i++) {
        int t, x;
        cin >> t >> x;
        lr[x - t].push_back(i + 1);
        rl[x + t].push_back(i + 1);
    }
    // y = x + c
    // x2 - x1 = t2 - t1
    // y = -x + c
    // x2 - x1 = t1 - t2
    vector<int> x(n + 1), y(n + 1);
    int tx = 1, ty;
    for (auto& it : lr) {
        for (auto& it2 : it.se) {
            x[it2] = tx;
        }
        ++tx;
    }
    ty = tx;
    for (auto& it : rl) {
        for (auto& it2 : it.se) {
            y[it2] = ty;
        }
        ++ty;
    }
    int S = 0, T = ty;
    solver.init();
    for (int i = 1; i < tx; i++) {
        solver.adde(S, i, 1);
    }
    for (int i = tx; i < ty; i++) {
        solver.adde(i, T, 1);
    }
    for (int i = 1; i <= n; i++) {
        solver.adde(x[i], y[i], 1);
    }
    int ans = solver.dinic(S, T);
    cout << ans << '\n';
}
int main() {
#ifdef Local
    freopen("input.in", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    int T; cin >> T; while(T--)
    run();
    return 0;
}

I. Imperative Meeting

题意:
给定一颗无根树,在上面放置\(m\)个人,然后他们会走到某个点上面去,代价为所有人经过的边数之和。
一共会有\(n\choose m\)种情况,现在要计算所有情况代价最小的和为多少。

思路:
显然直接算十分麻烦,因为枚举重心的话会涉及很多情况。所以转化一下思维:

  • 考虑每一条边的贡献。

对于一条边来说,假设一边有\(x\)个人,另外一边有\(y\)个人,\(x<y\),那么最优方案一定会贡献\(min(x,y)=x\)次,此时我们取树的重心为带权重心即可。
那么可以列出式子:

\[f(s)=\sum_{i=0}^m{s\choose i}{n-s\choose m-i}\cdot min(i, m-i) \]

这就是题解中的式子,因为式子中含有min,我们可以直接将其拆开,就有题解中的式子(令\(p=\frac{m-1}{2}\)):

\[f(s)=\sum_{i=1}^p({s\choose i}{n-s\choose m-i}\cdot i+{s\choose m-i}{n-s\choose i}\cdot i)+[m\% 2]\cdot {s\choose m/2}{n-s\choose m/2}\cdot(m/2) \]

后面那一部分暂时不用管,前面的两部分其实是具有对称性,我们令\(s'=n-s\)即可很轻松发现是具有对称关系的。
因此我们先考虑前一部分:\(\displaystyle g(s)=\sum_{i=1}^p{s\choose i}{n-s\choose m-i}\cdot i\),显然后面就等于\(g(n-s)\)
我们可以把\(i\)消去:\(\displaystyle g(s)=s\cdot \sum_{i=1}^p{s-1\choose i-1}{n-s\choose m - i}\)
我们可以给其赋予组合意义,就是\(n-1\)个盒子要放\(m-1\)个小球,前面\(s-1\)个位置最多放\(p-1\)个小球的方案数。
因为最后答案是跟\(s\)有关,注意这是一个前缀,其它数不会改变,那么就可以通过递推求得所有的\(g(s)\)
剩下的就简单了。

Code
// Author : heyuhhh
// Created Time : 2020/08/06 10:41:24
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
void err(int x) {cerr << x;}
void err(long long x) {cerr << x;}
void err(double x) {cerr << x;}
void err(char x) {cerr << '"' << x << '"';}
void err(const string &x) {cerr << '"' << x << '"';}
void _print() {cerr << "]\n";}
template<typename T, typename V>
  void err(const pair<T, V> &x) {cerr << '{'; err(x.first); cerr << ','; err(x.second); cerr << '}';}
template<typename T>
  void err(const T &x) {int f = 0; cerr << '{'; for (auto &i: x) cerr << (f++ ? "," : ""), err(i); cerr << "}";}
template <typename T, typename... V>
  void _print(T t, V... v) {err(t); if (sizeof...(v)) cerr << ", "; _print(v...);}
#ifdef Local
#define dbg(x...) cerr << "[" << #x << "] = ["; _print(x)
#else
#define dbg(x...)
#endif
//head
const int N = 1e6 + 5, MOD = 1e9 + 7;

int qpow(ll a, ll b) {
    ll res = 1;
    while(b) {
        if(b & 1) res = res * a % MOD;
        a = a * a % MOD;
        b >>= 1;   
    }
    return res;   
}
int fac[N], inv[N];
void init() {
    fac[0] = 1;
    for(int i = 1; i < N; i++) fac[i] = 1ll * fac[i - 1] * i % MOD;
    inv[N - 1] = qpow(fac[N - 1], MOD - 2);
    for(int i = N - 2; i >= 0; i--) inv[i] = 1ll * inv[i + 1] * (i + 1) % MOD;
}

int C(int n, int m) {
    if (n < m || n < 0 || m < 0) return 0;
    return 1ll * fac[n] * inv[m] % MOD * inv[n - m] % MOD;
}

void add(int& x, int y) {
    x += y;
    if (x >= MOD) x -= MOD;
}

int f[N], sz[N];
int n, m;
int ans[N];

void run() {
    cin >> n >> m;
    for (int i = 2; i <= n; i++) {
        cin >> f[i];
    }
    int p = (m - 1) / 2;
    ans[1] = C(n - 1, m - 1);
    for (int i = 2; i <= n; i++) {
        int t = 1ll * C(i - 2, p - 1) * C(n - i, m - 1 - p) % MOD;
        ans[i] = (ans[i - 1] - t + MOD) % MOD;
    }
    if (p == 0) {
        for (int i = 1; i <= n; i++) {
            ans[i] = 0;
        }
    }
    for (int i = 1; 2 * i <= n; i++) {
        ans[i] = 1ll * ans[i] * i % MOD + 1ll * ans[n - i] * (n - i) % MOD;
        ans[i] %= MOD;
    }
    for (int i = 1; i <= n; i++) {
        sz[i] = 1;
    }
    for (int i = n; i > 1; i--) {
        sz[f[i]] += sz[i];
    }
    int res = 0;
    for (int i = 1; i <= n; i++) {
        int s = sz[i];
        if (s < n) {
            add(res, ans[min(s, n - s)]);
            if (m % 2 == 0) {
                int tmp = 1ll * (m / 2) * C(s, m / 2) % MOD * C(n - s, m / 2) % MOD;
                add(res ,tmp);
            }
        }
    }
    cout << res << '\n';
}
int main() {
#ifdef Local
    freopen("input.in", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    init();
    int T; cin >> T; while(T--)
    run();
    return 0;
}

K. Kindergarten Physics

引力没啥影响,所以直接输出。

L. Last Problem

考虑递归进行构造,但是如果直接硬上的话可能时间会炸掉。但是稍微手模一下就会发现有很多共用的部分是不用管的,这样就节约掉了很大的时间。所以对于位置记忆化一下就行。当然还要选择一个较优的策略,但是这个策略其实挺多的。
相减代码:

Code
// Author : heyuhhh
// Created Time : 2020/07/30 20:05:17
#include<bits/stdc++.h>
#define MP make_pair
#define fi first
#define se second
#define pb push_back
#define sz(x) (int)(x).size()
#define all(x) (x).begin(), (x).end()
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef pair<int, int> pii;
//head
const int N = 5000 + 5;
int mp[N][N];
void run() {
    int n;
    cin >> n;
    vector<pair<pii, int>> ans;
    function <void(int, int, int)> draw = [&] (int x, int y, int n) {
        if (mp[x][y] == n) return;
        if (n <= 0) return;
        if (n == 1) {
            ans.emplace_back(MP(MP(x, y), 1));
            mp[x][y] = 1;
            return;
        }
        draw(x, y + 1, n - 1);
        draw(x - 1, y, n - 2);
        draw(x + 1, y, n - 3);
        draw(x, y - 1, n - 4);
        ans.emplace_back(MP(MP(x, y), n));
        mp[x][y] = n;
        return;
    };
    draw(2000, 2000, n);
    for (auto it : ans) {
        cout << it.fi.fi << ' ' << it.fi.se << ' ' << it.se << '\n';
    }
}
int main() {
#ifdef Local
    freopen("input.in", "r", stdin);
#endif
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    cout << fixed << setprecision(20);
    run();
    return 0;
}
posted @ 2020-08-09 15:31  heyuhhh  阅读(228)  评论(0编辑  收藏  举报