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;
    }
    
  • 相关阅读:
    POJ 2175 Evacuation Plan 费用流 负圈定理
    POJ 2983 Is the Information Reliable? 差分约束
    codeforces 420B Online Meeting
    POJ 3181 Dollar Dayz DP
    POJ Ant Counting DP
    POJ 1742 Coins DP 01背包
    中国儒学史
    产品思维30讲
    Java多线程编程核心技术
    编写高质量代码:改善Java程序的151个建议
  • 原文地址:https://www.cnblogs.com/WizardCowboy/p/7784835.html
Copyright © 2011-2022 走看看