zoukankan      html  css  js  c++  java
  • THUPC2018 城市地铁规划

    $n$ 个点,你可以随意连成一棵树,一个点的贡献为 $F(度数) space mod space 59393$ ,$F$ 为给定多项式函数,不超过 $10$ 次

    求这 $n$ 个点的最大贡献,和最后连出来的那棵树

    $n leq 3000$

    sol:

    看到这种跟树度数有关的题大概是要上 prufer 序列?

    对 prufer 序列进行 dp,每个点大概相当于一个物品,由于 prufer 序列可以任意放,大概还是个完全背包

    于是可以写出一个朴素的转移式:

    $f_{(i,j)}$ 表示 prufer 序列的前 $i$ 项,目前出现的最后一个数出现了 $j$ 次的最大贡献

    每次可以转移到 $f_{(i+1,j+1)}$ (填一个一样的)或者 $f_{(i+1,1)}$ (填一个新的)

    或者优秀一点(平时刷题啥都敢写系列),直接对于 prufer 序列上每一个位置,分配它连了多少个叶子,这样空间是一维的,也少了很多分类讨论

    后面把 prufer 序列变成一棵树就...用个 set 模拟一下就完事了

    #include<bits/stdc++.h>
    #define LL long long
    #define rep(i, s, t) for(register LL i = (s), i##end = (t); i <= i ## end; ++i)
    #define dwn(i, s, t) for(register LL i = (s), i##end = (t); i >= i ## end; --i)
    using namespace std;
    inline int read() {
        int x = 0, fv = 1; char ch = getchar();
        for(;!isdigit(ch);ch=getchar())if(ch == '-') fv=-fv;
        for(;isdigit(ch);ch=getchar())x = 10 * x + ch - '0';
        return x * fv;
    }
    const int maxn = 3010, mod = 59393;
    inline int inc(int x, int y) { x += y; if(x >= mod) x -= mod; return x; }
    inline int dec(int x, int y) { x -= y; if(x < 0) x += mod; return x; }
    inline int mul(int x, int y) { return 1LL * x * y % mod; }
    inline int power(int a, int b) {
        int res = 1;
        for (; b; b >>= 1, a = mul(a, a))
            if (b & 1) res = mul(res, a);
        return res;
    }
    int n, k, a[20], fv[maxn], p[maxn];
    LL f[maxn];
    inline int getval(int x) {
        int res = 0;
        for (int i = 0, j = 1; i <= k; j = mul(j, x), i++) res = inc(res, mul(j, a[i]));
        return res;
    }
    multiset<int> S, leaves;
    int main() {
        n = read(); k = read();
        rep(i, 0, k) a[i] = read();
        rep(i, 0, n) fv[i] = getval(i);
        if (n == 1) {
            cout << 0 << " " << a[0] << endl;
            return 0;
        }
        if (n == 2) {
            cout << 1 << " " << inc(fv[1], fv[1]) << endl << 1 << " " << 2 << endl;
            return 0;
        }
        rep(i, 1, n-2) rep(j, 1, i)
            if (f[i - j] + 1LL * fv[1] * (j - 1) + fv[j + 1] > f[i])
                f[i] = f[i - j] + 1LL * (j - 1) * fv[1] + fv[j + 1], p[i] = i - j;
        
        printf("%d %lld
    ", n-1, f[n-2] + fv[1] + fv[1]);
        for (int i = n - 2, j = i, cnt = 1; i; ++cnt, j = i = p[i])
            while (j > p[i]) S.insert(cnt), --j;
        rep(i, 1, n) if (!S.count(i)) leaves.insert(i);
        rep(i, 1, n-2) {
            int u = *leaves.begin(); leaves.erase(u);
            int v = *S.begin(); S.erase(S.find(v));
            printf("%d %d
    ", u, v);
            if (!S.count(v)) leaves.insert(v);
        }
        printf("%d %d
    ", *leaves.begin(), *leaves.rbegin());
    }
    View Code
  • 相关阅读:
    HDU 2844 Coins(多重背包)
    HDU 4540 威威猫系列故事——打地鼠(DP)
    Codeforces Round #236 (Div. 2)
    FZU 2140 Forever 0.5
    HDU 1171 Big Event in HDU(DP)
    HDU 1160 FatMouse's Speed(DP)
    ZOJ 3490 String Successor
    ZOJ 3609 Modular Inverse
    ZOJ 3603 Draw Something Cheat
    ZOJ 3705 Applications
  • 原文地址:https://www.cnblogs.com/Kong-Ruo/p/10559252.html
Copyright © 2011-2022 走看看