2020 Multi-University Training Contest 3

Contest Info


传送门

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

Solutions


A. Tokitsukaze, CSL and Palindrome Game

"掷骰子"类问题有个经典结论,假设我们要得到的序列长度为(L),字符集大小为(S)。那么我每次随机在后面添加一个字符,最后得到期望字符串(t)的期望次数为:

[sum_{i=1}^La_iS^i ]

其中(a_i)表示([1,cdots,i])是否为(t)串的border。
知道这个结论过后接下来就相当于比较给定两个串的(a_i)序列的字典序大小。
由于多组询问并且没有长度总和限制,就不能直接进行比较。
现在又有一个结论,一个字符串的border序列能被划分为logn段等差数列。
又由于palindrome border这套理论,一个串的最长回文后缀也是其一个border。由于这个题是回文串,那么把回文树建出来,一个字符串的最长回文后缀被划分为了logn段等差数列。那么我们直接在回文树上比较logn次就行。
细节见代码:

Code
// Author : heyuhhh
// Created Time : 2020/07/31 11:10:13
#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 << "]
";}
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 = 1e5 + 5;

namespace PAM{
    int ch[N][26], fail[N], len[N], st[N], cnt[N];
    int slink[N], diff[N];
    int val[N];
    int sz, n, last;
    // 0: len=0  1: len=-1
    int New(int l, int f) {
        memset(ch[++sz], 0, sizeof(ch[sz]));
        len[sz] = l, fail[sz] = f;
        diff[sz] = slink[sz] = 0;
        return sz;
    }
    void init() {
        sz = -1;
        New(0, 1); last = New(-1, 0);
        st[n = 0] = -1;
        memset(cnt, 0, sizeof(cnt));
    }
    int getf(int x) {
        while(st[n - len[x] - 1] != st[n]) x = fail[x];
        return x;
    }
    bool Insert(int c, int i) { //int
        st[++n] = c;
        int x = getf(last);
        bool F = 0;
        if(!ch[x][c]) {
            F = 1;
            int f = getf(fail[x]);
            int now;
            now = ch[x][c] = New(len[x] + 2, ch[f][c]);
            diff[now] = len[now] - len[fail[now]];
            if (diff[now] == diff[fail[now]]) slink[now] = slink[fail[now]];
            else slink[now] = fail[now];
        }
        last = ch[x][c];
        val[i] = last;
        cnt[last]++;
        return F;
    }

    int f[N][20];
    void build() {
        for (int i = 0; i <= sz; i++) {
            f[i][0] = fail[i];
        }
        for (int j = 1; j < 20; j++) {
            for (int i = 0; i <= sz; i++) {
                f[i][j] = f[f[i][j - 1]][j - 1];
            }
        }
    }
    int find(int x, int l) {
        x = val[x];
        for (int i = 19; i >= 0; i--) {
            if (len[f[x][i]] >= l) {
                x = f[x][i];
            }
        }
        return x;
    }
    int cmp(int u, int v) {
        while (u > 1 && v > 1) {
            if (len[u] != len[v]) {
                return len[u] > len[v] ? 1 : -1;
            }
            if (diff[u] != diff[v]) {
                return diff[u] < diff[v] ? 1 : -1;
            }
            if (len[u] - len[slink[u]] != len[v] - len[slink[v]]) {
                if (len[u] - len[slink[u]] > len[v] - len[slink[v]]) {
                    return diff[slink[v]] > diff[u] ? 1 : -1;
                } else {
                    return diff[slink[u]] > diff[v] ? -1 : 1;
                }
            }
            u = slink[u], v = slink[v];
        }
        if (u <= 1 && v <= 1) return 0;
        return u > v ? 1 : -1;
    }
};

void run() {
    PAM::init();
    int n;
    cin >> n;
    string s;
    cin >> s;
    for (int i = 0; i < n; i++) {
        PAM::Insert(s[i] - 'a', i);
    }
    PAM::build();
    int q;
    cin >> q;
    while (q--) {
        int a, b, c, d;
        cin >> a >> b >> c >> d;
        --a, --b, --c, --d;
        a = PAM::find(b, b - a + 1);
        b = PAM::find(d, d - c + 1);
        int cmp = PAM::cmp(a, b);
        if (cmp == -1) {
            cout << "sjfnb" << '
';
        } else if (cmp == 1) {
            cout << "cslnb" << '
';
        } else {
            cout << "draw" << '
';
        }
    }
}
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;
}

C. Tokitsukaze and Colorful Tree

题意:
给定一个(n)个结点的树,每个结点有两个属性:颜色和权值。然后有(q)次修改操作,要么修改颜色,要么修改权值。
问每次修改操作过后的答案为多少,答案计算方法为:

[sum_{1leq u<vleq n,col[u]=col[v],u,v不互为祖先}(val[u]oplus val[v]) ]

思路:
显然可以对每种颜色单独考虑,然后将异或拆位计算,我们只需要一位一位单独考虑,那么接下来只需要处理有多少个结点为(0,1)对并且不互相为祖先就行。
对于某个结点,显然要排除子树内的结点,和到根节点链上的结点。子树内就是一个区间问题,链的话可以直接树剖来解决。直接这样做复杂度貌似是三个log。
这里树剖其实可以省去,我们只需要修改链中的结点时,给其子树的结点打上贡献标记即可,这里相当于区间修改、单点查询,差分一下即可。那么对于一个结点一个是子树内的贡献,另一个是链上结点给他的贡献。
那么此时时间复杂度应该是两个log了,因为还要对每种颜色动态开个线段树,但这样做的话常数可能会比较大。所以我们直接离线对每种颜色处理即可,并且对每种操作增添一个“添加/删除”标记,写起来比较方便。
全程用树状数组,跑得挺快的。
详见代码:

Code
// Author : heyuhhh
// Created Time : 2020/07/29 15:30:54
#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;
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 << "]
";}
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

#define FI(x) FastIO::read(x)
#define FO(x) FastIO::write(x)
#define Flush FastIO::Fflush()
namespace FastIO {
    const int SIZE = 1 << 16;
    char buf[SIZE], obuf[SIZE], str[60];
    int bi = SIZE, bn = SIZE, opt;
    double D[] = {0.1, 0.01, 0.001, 0.0001, 0.00001, 0.000001, 0.0000001, 0.00000001, 0.000000001, 0.0000000001};
    int read(char *s) {
        while (bn) {
            for (; bi < bn && buf[bi] <= ' '; bi++);
            if (bi < bn) break;
            bn = fread(buf, 1, SIZE, stdin);
            bi = 0;
        }
        int sn = 0;
        while (bn) {
            for (; bi < bn && buf[bi] > ' '; bi++) s[sn++] = buf[bi];
            if (bi < bn) break;
            bn = fread(buf, 1, SIZE, stdin);
            bi = 0;
        }
        s[sn] = 0;
        return sn;
    }
    bool read(int& x) {
        int n = read(str), bf = 0;
        if (!n) return 0;
        int i = 0; if (str[i] == '-') bf = 1, i++; else if (str[i] == '+') i++;
        for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
        if (bf) x = -x;
        return 1;
    }
    bool read(long long& x) {
        int n = read(str), bf;
        if (!n) return 0;
        int i = 0; if (str[i] == '-') bf = -1, i++; else bf = 1;
        for (x = 0; i < n; i++) x = x * 10 + str[i] - '0';
        if (bf < 0) x = -x;
        return 1;
    }
    void write(int x) {
        if (x == 0) obuf[opt++] = '0';
        else {
            if (x < 0) obuf[opt++] = '-', x = -x;
            int sn = 0;
            while (x) str[sn++] = x % 10 + '0', x /= 10;
            for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
        }
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }
    void write(long long x) {
        if (x == 0) obuf[opt++] = '0';
        else {
            if (x < 0) obuf[opt++] = '-', x = -x;
            int sn = 0;
            while (x) str[sn++] = x % 10 + '0', x /= 10;
            for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
        }
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }
    void write(unsigned long long x) {
        if (x == 0) obuf[opt++] = '0';
        else {
            int sn = 0;
            while (x) str[sn++] = x % 10 + '0', x /= 10;
            for (int i = sn - 1; i >= 0; i--) obuf[opt++] = str[i];
        }
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }
    void write(char x) {
        obuf[opt++] = x;
        if (opt >= (SIZE >> 1)) {
            fwrite(obuf, 1, opt, stdout);
            opt = 0;
        }
    }
    void Fflush() { if (opt) fwrite(obuf, 1, opt, stdout); opt = 0;}
};

struct BIT {
    int c[N];
    int lowbit(int x) {
        return x & (-x);
    }
    void add(int x, int v) {
        for (; x < N; x += lowbit(x)) {
            c[x] += v;
        }
    }
    int query(int x) {
        int res = 0;
        for (;x > 0; x -= lowbit(x)) {
            res += c[x];
        }
        return res;
    }
    int query(int l, int r) {
        return query(r) - query(l - 1);
    }
}A[2], B[2];

struct node {
    int id, u, val, t;
};

int n;
vector<int> G[N];
vector<node> v[N];
int col[N], val[N];
int in[N], out[N], T;
ll ans[N];

void init() {
    for (int i = 1; i <= n; i++) {
        G[i].clear();
        v[i].clear();
    }
    T = 0;
}

void dfs(int u, int fa) {
    in[u] = ++T;
    for (auto v : G[u]) {
        if (v != fa) {
            dfs(v, u);
        }
    }
    out[u] = T;
}

void work(int color) {
    for (int bit = 0; bit < 20; bit++) {
        for (auto it : v[color]) {
            int u = it.u, id = it.id;
            int b = (it.val >> bit & 1);
            vector<int> num(2);
            num[0] = A[0].query(1, n) - (A[0].query(in[u], out[u]) + B[0].query(in[u]));
            num[1] = A[1].query(1, n) - (A[1].query(in[u], out[u]) + B[1].query(in[u]));
            // dbg(color, bit, num[0], num[1]);
            ans[id] += 1ll * num[b ^ 1] * (1 << bit) * it.t;
            A[b].add(in[u], it.t);
            B[b].add(in[u] + 1, it.t);
            B[b].add(out[u] + 1, -it.t);
        }
    }
}

void run() {
    FI(n);
    init();
    for (int i = 1; i <= n; i++) {
        FI(col[i]);
    }
    for (int i = 1; i <= n; i++) {
        FI(val[i]);
    }
    for (int i = 1; i <= n; i++) {
        v[col[i]].emplace_back(node{0, i, val[i], 1});
    }
    for (int i = 1; i < n; i++) {
        int u, v;
        FI(u), FI(v);
        G[u].emplace_back(v);
        G[v].emplace_back(u);
    }
    dfs(1, 0);
    int q; FI(q);
    for (int i = 1; i <= q; i++) {
        int op, x, y; 
        FI(op), FI(x), FI(y);
        v[col[x]].emplace_back(node{i, x, val[x], -1});
        if (op == 1) {
            val[x] = y;
        } else {
            col[x] = y;
        }
        v[col[x]].emplace_back(node{i, x, val[x], 1});
    }
    for (int i = 1; i <= n; i++) {
        v[col[i]].emplace_back(node{q + 1, i, val[i], -1});
    }
    for (int i = 1; i <= n; i++) {
        work(i);
    }
    for (int i = 1; i <= q; i++) {
        ans[i] += ans[i - 1];
    }
    for (int i = 0; i <= q; i++) {
        FO(ans[i]), FO('
');
        ans[i] = 0;
    }
}
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; FI(T); while(T--)
    run();
    Flush;
    return 0;
}

D. Tokitsukaze and Multiple

将问题转化为合并任意一段区间使得最终尽可能多的数的和为(p)的倍数。所以直接前缀和维护一下就行。

Code
// Author : heyuhhh
// Created Time : 2020/07/28 12:10:14
#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;
void run() {
    int n, p;
    cin >> n >> p;
    vector<int> a(n + 1);
    vector<int> sum(n + 1);
    for (int i = 1; i <= n; i++) {
        cin >> a[i];
        a[i] %= p;
    }
    for (int i = 1; i <= n; i++) {
        sum[i] = (sum[i - 1] + a[i]) % p;
    }
    vector<int> f(n + 1);
    vector<int> last(p, -1);
    last[0] = 0;
    for (int i = 1; i <= n; i++) {
        f[i] = f[i - 1];
        if (last[sum[i]] != -1) {
            f[i] = max(f[i], f[last[sum[i]]] + 1);
        }
        last[sum[i]] = i;
    }
    cout << f[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;
}

E. Little W and Contest

并查集瞎维护一下即可。
每次连边考虑减去不合法的情况。

Code
// Author : heyuhhh
// Created Time : 2020/07/28 14:04:45
#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;
void run() {
    string s;
    cin >> s;
    int n = s.length();
    int sum = 0;
    int Min = n + 1;
    for (int i = 0; i < n; i++) {
        if (s[i] == ')') --sum;
        if (s[i] == '(') ++sum;
        Min = min(Min, sum);
    }
    if (Min < 0) {
        for (int i = 0; i < n && Min < 0; i++) {
            if (s[i] == '*') {
                s[i] = '(';
                ++Min;
            }
        }
    }
    if (Min < 0) {
        cout << "No solution!" << '
';
        return;
    }
    
    sum = 0;
    for (int i = 0; i < n; i++) {
        if (s[i] == ')') --sum;
        if (s[i] == '(') ++sum;
    }
    for (int i = n - 1; i >= 0 && sum > 0; i--) {
        if (s[i] == '*') {
            s[i] = ')';
            --sum;
        }
    }
    sum = 0;
    Min = n + 1;
    for (int i = 0; i < n; i++) {
        if (s[i] == ')') --sum;
        if (s[i] == '(') ++sum;
        Min = min(Min, sum);
    }
    if (sum != 0 || Min < 0) {
        cout << "No solution!" << '
';
        return;
    }
    string res = "";
    for (int i = 0; i < n; i++) {
        if (s[i] != '*') res += s[i];
    }
    cout << res << '
';
}
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;
}

F. X Number

题意:
询问([l,r])区间中,数字(d)出现次数最多的数的个数为多少。
(1leq Tleq 1000,0leq dleq9)

思路:
这种很显然思路会往数位dp方向靠。但这个题和一般的数位dp不同的是数位个数很少。
数位dp的本质就是枚举位数所有情况,对于达到上限的就继续往下考虑,对于没达到上限的记忆化搜索。因为往往状态是有限个,所以复杂度一般是(O(数位*转移数*状态数))
但其实记忆化搜索的部分很灵活,只要我们能对当前“任意选”的情况计算出答案即可。比如我们可以使用组合计数那套或者其它类似dp都行。
回到这个题,因为数位很少,我们可以直接枚举出所有情况,即最大相等前缀以及后面一个数的大小,那么剩下的数可以任意取。因为前面(d)的个数已经固定,那么我们就知道后面(d)和其它的应该出现多少次。直接背包dp统计后面部分即可。
具体是枚举最后的最大数量(x),那么(d)出现的次数要达到(x),但是其余的最多只能到(x-1)。我们用(dp[i][j])表示前(i)个数确定了(j)个的合法方案数。剩下的就是对于每个数枚举其出现的次数然后组合数乘一乘就行。
注意前导(0)的情况需要特殊处理一下。

Code
// Author : heyuhhh
// Created Time : 2020/07/28 18:32:04
#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 << "]
";}
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 = 20;

int a[N], tot;
ll C[N][N];

void init() {
    C[0][0] = 1;
    for (int i = 1; i < N; i++) {
        C[i][0] = 1;
        for (int j = 1; j <= i; j++) {
            C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
        }
    }
}

ll calc(int s, vector<int>& cnt, int d, int lim, int t = tot) {
    if (lim) {
        if (s > t) return 0;
        ll res = 0;
        for (int i = 1; i < 10; i++) {
            ++cnt[i];
            res += calc(s + 1, cnt, d, 0);
            --cnt[i];
        }
        return res;
    }

    int now = cnt[d];
    int Max = 0;
    for (int i = 0; i < 10; i++) {
        if (i != d) Max = max(Max, cnt[i]);
    }

    int len = t - s + 1;
    if (len <= 0) {
        return Max < now;
    }

    ll res = 0;
    for (int x = max(now, Max + 1); x <= tot; x++) {
        vector<ll> f(len + 1);
        int t = x - now;
        if (t > len) continue;
        f[t] = C[len][t];
        for (int k = 0; k < 10; k++) {
            if (k == d) continue;
            for (int i = len; i > t; i--) {
                for (int j = t; j < i; j++) if (f[j] != 0) {
                    if (cnt[k] + i - j >= x) continue;
                    f[i] += C[len - j][i - j] * f[j];
                }
            }
        }
        res += f[len];
    }
    return res;
}

ll calc(ll x, int d) {
    tot = 0;
    ll t = x;
    while (t) {
        a[++tot] = t % 10;
        t /= 10;
    }
    reverse(a + 1, a + tot + 1);
    ll res = 0;
    for (int i = 1; i <= tot; i++) {
        vector<int> cnt(10);
        for (int j = 1; j < i; j++) {
            ++cnt[a[j]];
        }
        // 1 ~ i - 1匹配
        if (i == 1) {
            // 前导0
            for (int k = i + 1; k <= tot; k++) {
                res += calc(k, cnt, d, 1);
            }
        }
        int down = (i == 1 ? 1 : 0);
        int up = (i == tot ? 0 : 1);
        for (int j = down; j <= a[i] - up; j++) {
            ++cnt[j];
            res += calc(i + 1, cnt, d, 0);
            --cnt[j];
        }
    }
    return res;
}

void run() {
    ll l, r;
    int d;
    cin >> l >> r >> d;
    ll ans = calc(r, d) - calc(l - 1, d);
    cout << ans << '
';
}
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;
}

G. Tokitsukaze and Rescue

因为数据随机,所以最短路径长度期望不会很长,那么直接暴力找第(k)大最短路即可。
即每次枚举最短路上的边然后删去继续找最短路...

Code
#include<iostream>
#include<iomanip>
#include<cmath>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXN 57
typedef pair<int,int> pii;
int n,k;
int G[MAXN][MAXN];
int d[MAXN];
bool boom[MAXN][MAXN];
bool v[MAXN];
int fa[MAXN];
pii road[7][MAXN]; int roadn[7];
void dijkstra(pii *road, int&roadn) {
    const int o=1, t=n;
    memset(d,0x3f,sizeof d);
    memset(v,0,sizeof v);
    d[o]=0; fa[o]=-1;
    for(int i=1; i<n; i++) {
        int x=-1;
        for(int j=1; j<=n; j++) {
            if(!v[j] && (x==-1 || d[j]<d[x])) x=j;
        }
        v[x]=1;
        for(int y=1; y<=n; y++) if(!boom[x][y]) {
            int nd=d[x]+G[x][y];
            if(nd<d[y]) {
                d[y]=nd;
                fa[y]=x;
            }
        }
    }
    int cnt=0;
    for(int i=t; ~fa[i]; i=fa[i], cnt++, road++) {
        road->first=i, road->second=fa[i];
    }
    roadn=cnt;
}
int ans;
void dfs(int di) {
    if(di==k) {
        dijkstra(road[di],roadn[di]);
        ans=max(ans, d[n]);
        return;
    }
    dijkstra(road[di], roadn[di]);
    for(int i=0; i<roadn[di]; i++) {
        boom[road[di][i].first][road[di][i].second]=1;
        boom[road[di][i].second][road[di][i].first]=1;
        dfs(di+1);
        boom[road[di][i].first][road[di][i].second]=0;
        boom[road[di][i].second][road[di][i].first]=0;
    }
}
int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cout<<fixed<<setprecision(10);
    int T; cin>>T;
    while(0<T--) {
        memset(boom,0,sizeof boom);
        ans=0;
        cin>>n>>k;
        for(int i=0; i<n; i++) {
            for(int j=i+1; j<n; j++) {
                int u,v,w; cin>>u>>v>>w;
                G[u][v]=G[v][u]=w;
            }
        }
        dfs(0);
        cout<<ans<<'
';
    }
}

H. Triangle Collision

队友写的。

Code
#include<iostream>
#include<iomanip>
#include<cmath>
#include<algorithm>
using namespace std;
inline long double cross(long double x1, long double x2, long double y1, long double y2) {
    return x1*y2-x2*y1;
}
#define EPS 1e-6
int dcmp(long double x) {return (x>EPS)-(x<-EPS);}
int main() {
    ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
    cout<<fixed<<setprecision(10);
    int T; cin>>T;
    while(0<T--) {
        int L,vx,vy;
        long double x,y,L3,xx,yy,zz,vxx,vyy,vzz,t1,t2,t3,dt1,dt2,dt3;
        int k;
        cin>>L>>x>>y>>vx>>vy>>k;
        x+=L/2.0l;
        L3=L/sqrtl(2.0l);

        xx=x-1.0l/sqrtl(3.0l)*y, yy=2.0l/sqrtl(3.0l)*y;
        zz=cross(-xx,L-yy,L-xx,-yy)/L3/2;

        vxx=vx-1.0l/sqrtl(3.0l)*vy, vyy=2.0l/sqrtl(3.0l)*vy;
        vzz=cross(vxx,vyy,-1,1)/sqrtl(2.0l);

        t1=abs(L/vyy), t2=abs(L/vxx), t3=abs(L3/vzz);
#define vx none
#define vy none
#define vz none
        if(dcmp(vxx)<0) dt2=xx/-vxx;
        else if(dcmp(vxx)>0) dt2=(L-xx)/vxx;

        if(dcmp(vyy)<0) dt1=yy/-vyy;
        else if(dcmp(vyy)>0) dt1=(L-yy)/vyy;

        if(dcmp(vzz)<0) dt3=(L3+zz)/-vzz;
        else if(dcmp(vzz)>0) dt3=-zz/vzz;
#define L fadsfsa
        long double L=0, R=1e11;
        while((R-L)>1e-5) {
            long double M=L+(R-L)/2;
            long long cnt=0;
            if(dcmp(vyy)!=0 && dcmp(M-dt1)>=0) {
                cnt++;
                cnt+=(long long)(floor((M-dt1)/t1)+0.1);
            }
            if(dcmp(vxx)!=0 && dcmp(M-dt2)>=0) {
                cnt++;
                cnt+=(long long)(floor((M-dt2)/t2)+0.1);
            }
            if(dcmp(vzz)!=0 && dcmp(M-dt3)>=0) {
                cnt++;
                cnt+=(long long)(floor((M-dt3)/t3)+0.1);
            }
            if(cnt>=k) R=M;
            else L=M;
        }
        cout<<L<<'
';

    }
}

I. Parentheses Matching

贪心。

Code
// Author : heyuhhh
// Created Time : 2020/07/28 14:04:45
#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;
void run() {
    string s;
    cin >> s;
    int n = s.length();
    int sum = 0;
    int Min = n + 1;
    for (int i = 0; i < n; i++) {
        if (s[i] == ')') --sum;
        if (s[i] == '(') ++sum;
        Min = min(Min, sum);
    }
    if (Min < 0) {
        for (int i = 0; i < n && Min < 0; i++) {
            if (s[i] == '*') {
                s[i] = '(';
                ++Min;
            }
        }
    }
    if (Min < 0) {
        cout << "No solution!" << '
';
        return;
    }
    
    sum = 0;
    for (int i = 0; i < n; i++) {
        if (s[i] == ')') --sum;
        if (s[i] == '(') ++sum;
    }
    for (int i = n - 1; i >= 0 && sum > 0; i--) {
        if (s[i] == '*') {
            s[i] = ')';
            --sum;
        }
    }
    sum = 0;
    Min = n + 1;
    for (int i = 0; i < n; i++) {
        if (s[i] == ')') --sum;
        if (s[i] == '(') ++sum;
        Min = min(Min, sum);
    }
    if (sum != 0 || Min < 0) {
        cout << "No solution!" << '
';
        return;
    }
    string res = "";
    for (int i = 0; i < n; i++) {
        if (s[i] != '*') res += s[i];
    }
    cout << res << '
';
}
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;
}
原文地址:https://www.cnblogs.com/heyuhhh/p/13462857.html