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;
}
原文地址:https://www.cnblogs.com/RiverHamster/p/sol-loj6395.html