zoukankan      html  css  js  c++  java
  • 2020 2.4

    t1

    给出一个图,求图中所有不同有根树的权值之和。

    定义有根树权值为

     d表示点的深度,根的深度为0.

    n<=10 m<=1000

    题解

    还是类似于宝藏的状压。f[t][i][j]表示叶子距离根节点距离为t,非叶子节点为状态i,叶子节点为状态j,权值的和,g[t][i][j]表示方案数。

    f[t][i][j]就可以转移到f[t+1][i|j][k](k和i|j不相交),需要预处理出叶节点为j转移到叶节点为k的权值和,方案数。

    代码如下:

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    int n, m, x[2020], y[2020], w[2020], p = 1000000007;
    int f[11][1025][1025]; // cnt
    int g[11][1025][1025]; // sum
    ll c[1025][1025];
    ll s[1025][1025];
    int main() {
        scanf("%d%d", &n, &m);
        for (int i = 0; i < m; i++) {
            scanf("%d%d%d", &x[i], &y[i], &w[i]);
            x[i]--;
            y[i]--;
            x[i + m] = y[i];
            y[i + m] = x[i];
            w[i + m] = w[i];
        }
        m *= 2;
        for (int i = 0; i < 1 << n; i++) {
            for (int j = 0; j < 1 << n; j++) {
                if (i & j) {
                    continue;
                }
                ll ts[11] = {};
                ll tc[11] = {};
                for (int k = 0; k < m; k++) {
                    if ((i >> x[k] & 1) && (j >> y[k] & 1)) {
                        tc[y[k]]++;
                        ts[y[k]] += w[k];
                    }
                }
                c[i][j] = 1;
                s[i][j] = 0;
                for (int k = 0; k < n; k++) {
                    if (j >> k & 1) {
                        c[i][j] *= tc[k];
                    }
                }
                if (c[i][j] == 0) {
                    continue;
                }
                for (int k = 0; k < n; k++) {
                    if (j >> k & 1) {
                        s[i][j] += c[i][j] / tc[k] * ts[k];
                    }
                }
            }
        }
        for (int i = 0; i < n; i++) {
            f[0][0][1 << i] = 1;
            g[0][0][1 << i] = 0;
        }
        for (int t = 0; t < n; t++) {
            for (int i = 0; i < 1 << n; i++) {
                for (int j = 0; j < 1 << n; j++) {
                    if (i & j) {
                        continue;
                    }
                    if (f[t][i][j] == 0) {
                        continue;
                    }
                    int mask = (1 << n) - 1 - i - j;
                    for (int k = mask;; k = (k - 1) & mask) {
                        ll gc = (ll)g[t][i][j] * c[j][k];
                        ll fc = (ll)f[t][i][j] * c[j][k];
                        ll fs = (ll)f[t][i][j] * s[j][k] * (t + 1);
                        f[t + 1][i | j][k] = (f[t + 1][i | j][k] + fc) % p;
                        g[t + 1][i | j][k] = (g[t + 1][i | j][k] + gc + fs) % p;
                        if (k == 0) {
                            break;
                        }
                    }
                }
            }
        }
        printf("%d
    ", g[n][(1 << n) - 1][0]);
        return 0;
    }
    View Code

    t2 略

    t3

    4 个字符串,求LCS。每个字符串中,前三个每个数字⾄多出现2 次。

    n<=10000.

    可以记录前三个字符串每个数字出线的位置,在第四个字符串找到数d[i]时,在前三个里各取一个位置a[i].b[i],c[i]来与d[i]构成一个点。因为前面每个最多出现两次,所以最多8n个点,跑四位正序。

    代码如下:

    #include <bits/stdc++.h>
    
    #define MAXN 200005
    
    using namespace std;
    
    int n, BIT[MAXN], ans, turn;
    
    struct Data{
        int id, a, b, c;
        bool type; // false change / true query
    }op[4][MAXN];
    
    int f[MAXN];
    bool cmp(const Data &A, const Data &B) {
        if (turn == 1) {
            if (A.a != B.a) {
                return A.a < B.a;
            }
            if (A.b != B.b) {
                return A.b > B.b;
            }
            return A.c > B.c;
        }
        if (turn == 2A) {
            if (A.b != B.b) {
                return A.b < B.b;
            }
            return A.c > B.c;
        }
        assert(false);
    }
    
    int lowbit(int x){
        return x & (-x);
    }
    
    void clear(int x) {
        x++;
        for (int i = x; i <= MAXN; i += i & -i) {
            BIT[i] = 0;
        }
    }
    
    void change(int x, int v) {
        x++;
        for (int i = x; i <= MAXN; i += i & -i) {
            BIT[i] = max(BIT[i], v);
        }
    }
    
    int query(int x) {
        x++;
        int re = 0;
        for (int i = x; i > 0; i -= i & -i) {
            re = max(re, BIT[i]);
        }
        return re;
    }
    
    void Work(int cnt) {
    //    printf("start
    ");
        for (int i = 0; i < cnt; i++) {
    //        printf("d%d %d %d %d %d
    ", op[2][i].id, op[2][i].a, op[2][i].b, op[2][i].c, op[2][i].type);
            if (!op[2][i].type) {
                change(op[2][i].c, f[op[2][i].id]);
            } else {
                f[op[2][i].id] = max(f[op[2][i].id], query(op[2][i].c - 1) + 1);
            }
        }
        for (int i = 0; i < cnt; i++) {
            if (!op[2][i].type) {
                clear(op[2][i].c);
            }
        }
    //    printf("end
    ");
    }
    
    void CDQ(int now, int L, int R) {
        if (R - L <= 1) {
            return;
        }
        int mid = (L + R) / 2;
        int cnt = 0;
        CDQ(now, L, mid);
    
        for (int i = L; i < mid; i++) {  
            if (now == 1) {
                op[now][cnt] = op[now - 1][i];
                op[now][cnt].type = false;
                cnt++;
            } else if (!op[now - 1][i].type) {
                op[now][cnt] = op[now - 1][i];
                cnt++;
            }
        }
        for (int i = mid; i < R; i++) {
            if (now == 1) {
                op[now][cnt] = op[now - 1][i];
                op[now][cnt].type = true;
                cnt++;
            } else if (op[now - 1][i].type) {
                op[now][cnt] = op[now - 1][i];
                cnt++;
            }
        }
    
        turn = now;
        sort(op[now], op[now] + cnt, cmp);
        if(now == 2) {
    //        printf("%d %d %d %d
    ", now, L, R, cnt);
            Work(cnt);
        } else {
            CDQ(now + 1, 0, cnt);
        }
        CDQ(now, mid, R);
    }
    
    
    int A[50020];
    int B[50020];
    int C[50020];
    int D[50020];
    vector<int> pA[50020];
    vector<int> pB[50020];
    vector<int> pC[50020];
    void read() {
        int N;
        scanf("%d", &N);
        for (int i = 0; i < N; i++) {
            scanf("%d", &A[i]);
            pA[A[i]].push_back(i);
        }
        for (int i = 0; i < N; i++) {
            scanf("%d", &B[i]);
            pB[B[i]].push_back(i);
        }
        for (int i = 0; i < N; i++) {
            scanf("%d", &C[i]);
            pC[C[i]].push_back(i);
        }
        for (int i = 0; i < N; i++) {
            scanf("%d", &D[i]);
            for (int ja = 0; ja < pA[D[i]].size(); ja++) {
                int pa = pA[D[i]][ja];
                for (int jb = 0; jb < pB[D[i]].size(); jb++) {
                    int pb = pB[D[i]][jb];
                    for (int jc = 0; jc < pC[D[i]].size(); jc++) {
                        int pc = pC[D[i]][jc];
                        op[0][n] = {n, pa, pb, pc, false};
                        n++;
                    }
                }
            }
        }
    
    }
    int main(){
        read();
        for (int i = 0; i < n; i++) {
    //        printf("%d %d %d %d
    ", op[0][i].id, op[0][i].a, op[0][i].b, op[0][i].c);
        }
        for (int i = 0; i < n; i++) {
            f[i] = 1;
        }
        CDQ(1, 0, n);
        int ans = 0;
        for (int i = 0; i < n; i++) {
            ans = max(ans, f[i]);
        }
    //    fprintf(stderr, "n = %d
    ", n);
        printf("%d
    ", ans);
        return 0;
    } 
    View Code
  • 相关阅读:
    The hardest problem ever
    1146 Topological Order
    1147 Heaps
    Weekly Contest 184
    1148 Werewolf
    1149 Dangerous Goods Packaging
    1150 Travelling Salesman Problem
    1151 LCA in a Binary Tree (30point(s))
    1152 Google Recruitment
    美团2020春招笔试
  • 原文地址:https://www.cnblogs.com/betablewaloot/p/12271070.html
Copyright © 2011-2022 走看看