zoukankan      html  css  js  c++  java
  • [Codeforces178F2]Representative Sampling

    Problem

    给定n个字符串Si,任意选出k个字符串Ai,使得其中任意两个字符串lcp之和最大。

    Solution

    建一棵trie树,枚举每一个节点对答案的贡献,树形dp,时间复杂度像是O(N^3)
    由于每个点对只在自己LCA的时候枚举到贡献,所以是O(N^2)

    Notice

    这道题分析时间复杂度十分重要

    Code

    #include<cmath>
    #include<cstdio>
    #include<cstring>
    #include<iostream>
    #include<algorithm>
    using namespace std;
    #define sqz main
    #define ll long long
    #define reg register int
    #define rep(i, a, b) for (reg i = a; i <= b; i++)
    #define per(i, a, b) for (reg i = a; i >= b; i--)
    #define travel(i, u) for (reg i = head[u]; i; i = edge[i].next)
    const int INF = 1e9, N = 2000, M = N * 500;
    const double eps = 1e-6, phi = acos(-1);
    ll mod(ll a, ll b) {if (a >= b || a < 0) a %= b; if (a < 0) a += b; return a;}
    ll read(){ ll x = 0; int zf = 1; char ch; while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
    if (ch == '-') zf = -1, ch = getchar(); while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar(); return x * zf;}
    void write(ll y) { if (y < 0) putchar('-'), y = -y; if (y > 9) write(y / 10); putchar(y % 10 + '0');}
    int S = 0, num = 0, cnt[M + 5], deep[M + 5], head[M + 5], F[N * 2 + 5][N + 5], Size[M + 5], son[M][26];
    char st[N + 5];
    struct node
    {
        int vet, next, val;
    }edge[2 * M];
    void add(int u, int v, int w)
    {
        edge[++num].vet = v;
        edge[num].next = head[u];
        edge[num].val = w;
        head[u] = num;
    }
    void dfs(int u, int fa, int last)
    {
        deep[u] = deep[fa] + 1;
        int tot = cnt[u];
        rep(i, 0, 25)
            if (son[u][i]) tot++;
        if (tot != 1 || cnt[u]) add(last, u, deep[u] - deep[last]);
        rep(i, 0, 25)
            if (son[u][i])
                    if (tot == 1 && !cnt[u]) dfs(son[u][i], u, last);
                    else dfs(son[u][i], u, u);
    }
    int dp(int u, int fa, int len)
    {
        int now = ++S;
        Size[u] = cnt[u];
        per(i, cnt[u], 1) F[now][i] = i * (i - 1) / 2 * len;
        travel(i, u)
        {
            int v = edge[i].vet;
            if (v == u) continue;
            int pre = dp(v, u, edge[i].val);
            Size[u] += Size[v];
            per(j, Size[u], 1)
                rep(k, 1, min(j, Size[v]))
                    F[now][j] = max(F[now][j], F[now][j - k] + F[pre][k] + len * (j - k) * k + len * k * (k - 1) / 2);
        }
        return now;
    }
    int sqz()
    {
        memset(head, 0, sizeof head);
        int n = read(), m = read(), point = 0;
        rep(i, 1, n)
        {
            scanf("%s", st + 1);
            int len = strlen(st + 1), now = 0;
            rep(j, 1, len)
            {
                if (!son[now][st[j] - 'a']) son[now][st[j] - 'a'] = ++point;
                now = son[now][st[j] - 'a'];
            }
            cnt[now]++;
        }
        dfs(0, -1, 0);
        dp(0, -1, 0);
        printf("%d
    ", F[1][m]);
        return 0;
    }
    
  • 相关阅读:
    树链剖分求LCA
    洛谷P1019 单词接龙
    洛谷P1441 砝码称重
    洛谷P2347 砝码称重
    洛谷P1164 小A点菜
    洛谷P2202 [USACO13JAN]方块重叠Square Overlap
    黑客与画家 第四章
    黑客与画家 第十二章
    记录最近一段的体会
    11.5最小生成树(Minimum Spanning Trees)
  • 原文地址:https://www.cnblogs.com/WizardCowboy/p/7784835.html
Copyright © 2011-2022 走看看