E2. PermuTree (hard version)

You are given a tree with nn vertices rooted at vertex 11.

For some permutation†† aa of length nn, let f(a)f(a) be the number of pairs of vertices (u,v)(u,v) such that au

Find the maximum possible value of f(a)f(a) over all permutations aa of length nn.

†† A permutation of length nn is an array consisting of nn distinct integers from 11 to nn in arbitrary order. For example, [2,3,1,5,4][2,3,1,5,4] is a permutation, but [1,2,2][1,2,2] is not a permutation (22 appears twice in the array), and [1,3,4][1,3,4] is also not a permutation (n=3n=3 but there is 44 in the array).

Input

The first line contains a single integer nn (2≤n≤1062≤n≤106).

The second line contains n−1n−1 integers p2,p3,…,pnp2,p3,…,pn (1≤pi

Output

Output the maximum value of f(a)f(a).

Examples

input

Copy

5
1 1 3 3

output

Copy

4

input

Copy

2
1

output

Copy

0

input

Copy

6
1 2 2 1 5

output

Copy

7

input

Copy

4
1 1 1

output

Copy

2

Note

The tree in the first test:

E2. PermuTree (hard version)_第1张图片

One possible optimal permutation aa is [2,1,4,5,3][2,1,4,5,3] with 44 suitable pairs of vertices:

  • (2,3)(2,3), since lca(2,3)=1lca⁡(2,3)=1 and 1<2<41<2<4,
  • (2,4)(2,4), since lca(2,4)=1lca⁡(2,4)=1 and 1<2<51<2<5,
  • (2,5)(2,5), since lca(2,5)=1lca⁡(2,5)=1 and 1<2<31<2<3,
  • (5,4)(5,4), since lca(5,4)=3lca⁡(5,4)=3 and 3<4<53<4<5.

The tree in the third test:

E2. PermuTree (hard version)_第2张图片

The tree in the fourth test:

E2. PermuTree (hard version)_第3张图片

题目的本质要求就是从一堆数中选出某些数,使这些数和剩下的数相乘的结果是最大的

首先可以考虑状压dp用位运算的形式去枚举 ,求出一些数

if (n <= 6) {
		long long res = 0;
		for (int mask = 0; mask < (1 << n); mask++) {
			int z = 0;
			for (int i = 0; i < n; i++) {
				if ((mask >> i) & 1) z += a[i];
			}
			res = max(res, 1LL * z * (s - z));
		}
		return res;
	}

但是又会面临一个问题就是n太大无法一个个的去枚举

那我们可以用二进制的方式来表示他所能到达的位置

假设原来是a=[2,3,1]

         8 7 6 5 4 3 2 1 0

 dp=  0 0 0 0 0 0 0 0 1

如上,开始时第0位是0表示他能到达第0个位置

然后通过枚举原来的数组       dp |= dp << x

000000001->000000101->000101101->001111111

 8 7 6 5 4 3 2 1 0

 0 0 1 1 1 1 1 1 1

综上可以知道能到达6 5 4 3 2 1 0

然后我们去遍历所能到达的位置求一个最佳状态

template
long long calc_bs(vector& a) {//a储存原数组
	bitset dp;
	int s = accumulate(a.begin(), a.end(), 0);
	dp[0] = 1;
	for (int x : a) dp |= dp << x;
	long long res = 0;
	for (int i = 0; i < s; i++) {
		if (dp[i]) res = max(res, 1LL * i * (s - i));
	}
	return res;
}

 但是按照下面这样写会超时

t的原因是进行太多次位运算了,中间有一堆不必要的运算耗费大量的时间

分析中间的原因

#include
#define PII pair
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f3f, N = 1e6 + 5, mod = 1e9 + 7;
vectorG[N];
int n, sz[N], p[N];
template
long long calc_bs(vector& a) {
	bitset dp;
	int s = accumulate(a.begin(), a.end(), 0);
	dp[0] = 1;
	for (int x : a) dp |= dp << x;
	long long res = 0;
	for (int i = 0; i < s; i++) {
		if (dp[i]) res = max(res, 1LL * i * (s - i));
	}
	return res;
}
long long calc(vector& a) {
	if (a.empty()) return 0;
	int s = accumulate(a.begin(), a.end(), 0);
	int n = a.size();
	if (a.back() >= s / 2) return 1LL * a.back() * (s - a.back());
	if (n <= 6) {
		long long res = 0;
		for (int mask = 0; mask < (1 << n); mask++) {
			int z = 0;
			for (int i = 0; i < n; i++) {
				if ((mask >> i) & 1) z += a[i];
			}
			res = max(res, 1LL * z * (s - z));
		}
		return res;
	}
	if (s <= 100) return calc_bs<105>(a);
	else if(s <= 1000) return calc_bs<1005>(a);
	else if (s <= 10000) return calc_bs<10005>(a);
	else if (s <= 100000) return calc_bs<100005>(a);
	else return calc_bs<1000005>(a);
}
signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	cin >> n;
	for (int i = 2; i <= n; i++) {
		cin >> p[i];
		G[p[i]].push_back(i);
	}
	fill(sz + 1, sz + n + 1, 1);
	for (int i = n; i >= 2; i--) sz[p[i]] += sz[i];
	long long ans = 0;
	for (int i = 1; i <= n; i++) {
		vector a;
		for (int v : G[i]) a.emplace_back(sz[v]);
		ans += calc(a);
	}
	cout << ans << '\n';
}

 

就是假如你有2个1的话你肯定想分成1 *1

3个1的话分成(1+1)*1

5个的话(1+1)*((1+1)+1)

于是我们可以将连续出现的3个数中分成a,a+a

借助优先队列的出队入队来进行排序

下面就是完整的代码

#include
#define PII pair
using namespace std;
const int inf = 0x3f3f3f3f3f3f3f3f, N = 1e6 + 5, mod = 1e9 + 7;
vectorG[N];
int n, sz[N], p[N];
void compress(vector& a) {
	priority_queue, greater> pq;
	for (int x : a) pq.emplace(x);
	a.clear();
	while (!pq.empty()) {
		int x = pq.top();
		pq.pop();
		if (a.size() >= 2 && a[(int)a.size() - 2] == x) {
			a.pop_back();
			pq.emplace(2 * x);
		}
		else a.emplace_back(x);
	}
}
template
long long calc_bs(vector& a) {
	bitset dp;
	int s = accumulate(a.begin(), a.end(), 0);
	dp[0] = 1;
	for (int x : a) dp |= dp << x;
	long long res = 0;
	for (int i = 0; i < s; i++) {
		if (dp[i]) res = max(res, 1LL * i * (s - i));
	}
	return res;
}
long long calc(vector& a) {
	if (a.empty()) return 0;
	compress(a);
	int s = accumulate(a.begin(), a.end(), 0);
	int n = a.size();
	if (a.back() >= s / 2) return 1LL * a.back() * (s - a.back());
	if (n <= 6) {
		long long res = 0;
		for (int mask = 0; mask < (1 << n); mask++) {
			int z = 0;
			for (int i = 0; i < n; i++) {
				if ((mask >> i) & 1) z += a[i];
			}
			res = max(res, 1LL * z * (s - z));
		}
		return res;
	}
	if (s <= 100) return calc_bs<105>(a);
	else if(s <= 1000) return calc_bs<1005>(a);
	else if (s <= 10000) return calc_bs<10005>(a);
	else if (s <= 100000) return calc_bs<100005>(a);
	else return calc_bs<1000005>(a);
}
signed main()
{
	ios_base::sync_with_stdio(0); cin.tie(0), cout.tie(0);
	cin >> n;
	for (int i = 2; i <= n; i++) {
		cin >> p[i];
		G[p[i]].push_back(i);
	}
	fill(sz + 1, sz + n + 1, 1);
	for (int i = n; i >= 2; i--) sz[p[i]] += sz[i];
	long long ans = 0;
	for (int i = 1; i <= n; i++) {
		vector a;
		for (int v : G[i]) a.emplace_back(sz[v]);
		ans += calc(a);
	}
	cout << ans << '\n';
}

你可能感兴趣的:(数据库)