zoukankan      html  css  js  c++  java
  • LOJ6395 「THUPC2018」城市地铁规划 / City

    思路

    很明显 prufer 序列,度数为 (d_i) 的点在 prufer 序列中出现的次数为 (d_i - 1)

    代入 (n) 个值得出每个度数的价值,问题就是要背包出 (n - 2) 个点,求最大的价值。

    可以 (mathcal O(n^2 log n)) 倍增 DP,但有更优的做法。

    先假设序列中没有任何元素,则每个点都是叶子,答案是 (n cdot f(1)),然后 DP 一个点加入多少个,设某个点加入了 (i) 个,价值就是 (f(i) - f(1)),因为它不再是叶子了 ,费用是 (i)

    完全背包出 (n - 2) 个点最优方案,然后构造出序列,再构造树即可。

    注意特判一下 (n = 1),因为不存在 prufer 序列。

    Code

    #include <cstdio>
    #include <cctype>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    using namespace std;
    #define File(s) freopen(s".in", "r", stdin), freopen(s".out", "w", stdout)
    typedef long long ll;
    template<typename T> inline void gi(T &x){
    	char ch; x = 0;
    	int f = 1;
    	while(isspace(ch = getchar()));
    	if(ch == '-') ch = getchar(), f = -1;
    	do x = x * 10 + ch - '0'; while(isdigit(ch = getchar()));
    	x *= f;
    }
    template<class T> void upmax(T &x, T y){x = x>y ? x : y;}
    template<class T> void upmin(T &x, T y){x = x<y ? x : y;}
    const int N = 5000, K = 15, mod = 59393;
    int coef[K];
    int n, k;
    
    int getVal(int x){
    	int res = 0;
    	for(int i=k; i>=0; i--)
    		res = (res * x + coef[i]) % mod;
    	return res;
    }
    
    int f[N], tr[N], g[N];
    int pru[N], pc = 0, idc = 0, cnt[N];
    
    int main(){
    	int n;
    	gi(n); gi(k);
    	if(n == 1) {
    		int x; gi(x);
    		printf("0 %d
    ", x); return 0;
    	}
    	for(int i=0; i<=k; i++) gi(coef[i]);
    	for(int i=1; i<n; i++) g[i] = getVal(i);
    
    	for(int i=1; i<=n-2; i++)
    		for(int j=i; j<=n-2; j++){
    			if(f[j - i] + g[i + 1] - g[1] > f[j]){
    				f[j] = f[j - i] + g[i + 1] - g[1];
    				tr[j] = i;
    			}
    		}
    
    	priority_queue<int, vector<int>, greater<int> > S;
    	for(int i=n-2; i;){
    		++idc; cnt[idc] = tr[i];
    		for(int j=1; j<=tr[i]; j++) pru[++pc] = idc;
    		i -= tr[i];
    	}
    	for(int i=idc+1; i<=n; i++)
    		S.push(i);
    	printf("%d %d
    ", n - 1, f[n - 2] + g[1] * n);
    	for(int i=1; i<=n-2; i++){
    		int x = S.top(); S.pop();
    		printf("%d %d
    ", x, pru[i]);
    		--cnt[pru[i]];
    		if(cnt[pru[i]] == 0) S.push(pru[i]);
    	}
    	printf("%d ", S.top()); S.pop();
    	printf("%d
    ", S.top());
    	return 0;
    }
    
  • 相关阅读:
    zbb20180930 Postman 使用方法详解
    Cookie、Session、jsp、EL、JSTL
    Http协议、Tomcat、servlet
    xml、网络编程、 反射
    JDBC、DBUtils
    Java IO流对象、多线程
    mySql
    Java基础
    VueJs
    GIT
  • 原文地址:https://www.cnblogs.com/RiverHamster/p/sol-loj6395.html
Copyright © 2011-2022 走看看