• 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;
    }
    
  • 相关阅读:
    [No0000161]IDEA初步接触
    [No0000171]wpf 类层次结构Class Hierarchy
    [No0000160]常用C# 正则表达式大全
    [No000015D]【李笑来 笔记整理】个人商业模式升级
    thinkphp 系统变量
    thinkphp不读取.env文件的键对值
    thinkphp 模板变量输出替换和赋值
    thinkphp 视图view
    thinkphp 响应对象response
    Thinkphp 请求和响应
  • 原文地址:https://www.cnblogs.com/heyuhhh/p/13462857.html
Copyright © 2020-2023  润新知