SCU4441 Necklace

Necklace

frog has \(n\) gems arranged in a cycle, whose beautifulness are \(a_1,a_2,...,a_n\). She would like to remove some gems to make them into a beautiful necklace without changing their relative order.

Note that a beautiful necklace can be divided into \(3\) consecutive parts \(X,y,Z\) where

\(X\) consists of gems with non-decreasing beautifulness,
\(y\) is the only perfect gem. (A perfect gem is a gem whose beautifulness equals to 1000010000)
\(Z\) consists of gems with non-increasing beautifulness.
Find out the maximum total beautifulness of the remaining gems.

Input

The input consists of multiple tests. For each test:

The first line contains \(1\) integer \(n\) \((1 \leq n \leq 10^5)\)
.$ The second line contains \(n\) integers \(a_1,a_2,...,a_n\). \((0 \leq a_i \leq 10^4,1 \leq number~of ~perfect~gems \leq 10)\).

Output

For each test, write \(1\) integer which denotes the maximum total remaining beautifulness.

考点:dp + 树状数组

思路:首先看到只有至多\(10\)个完美的宝石,可以考虑直接暴力以这\(10\)个宝石为分界线搞dp(显然),怎么处理环呢?之前学最小表示法的时候就学到过一个很好的解决环的方法:将序列二倍,然后任找一个起点去数\(n\)个显然就是环了。至于dp是\(10^5\)级别的\(O(n^2)\),怎么办呢?考虑用权值树状数组去记录最大的\(f[i]\),这样就可以将dp优化到\(O(nlogn)\)了。

#include <bits/stdc++.h>

using namespace std;

const int N = 1e5 + 5;

int a[N << 1], c[N], f[N], g[N], b[N], n;

void modify(int x, int k)
{
	for (int i = x; i <= 10000; i += (i & -i)) c[i] = max(c[i], k);
}

int query(int x)
{
	int ans = 0;
	for (int i = x; i >= 1; i -= (i & -i)) ans = max(ans, c[i]);
	return ans;
}

inline int gett(int u)
{
	memset(c, 0, sizeof c), memset(f, 0, sizeof f), memset(g, 0, sizeof g);
	int cnt = 0, ans = 0;
	for (int i = u + 1; i < u + n; i++) if (a[i] ^ 10000) b[++cnt] = a[i];
    f[1] = b[1];
	modify(10000 - b[1], b[1]); 
	for (int i = 2; i <= cnt; i++) f[i] = query(10000 - b[i]) + b[i], modify(10000 - b[i], f[i]);
	memset(c, 0, sizeof c);
	g[cnt] = b[cnt];
	modify(10000 - b[cnt], b[cnt]);
	for (int i = cnt - 1; i >= 1; i--) g[i] = query(10000 - b[i]) + b[i], modify(10000 - b[i], g[i]);
	for (int i = 2; i <= cnt; i++) f[i] = max(f[i], f[i - 1]);
	for (int i = cnt - 1; i > 1; i--) g[i] = max(g[i], g[i + 1]);
	for (int i = 1; i <= cnt; i++) ans = max(ans, f[i] + g[i + 1]); 
	ans = max(ans, g[1]);
	return ans + 10000;
}

int main()
{
	while (~scanf("%d", &n))
	{
		for (int i = 1; i <= n; i++) 
		{
			scanf("%d", &a[i]), a[i + n] = a[i];
		} int ans = 0;
		for (int i = 1; i <= n; i++)
		{
			if (a[i] == 10000) ans = max(ans, gett(i));
		} printf("%d\n", ans);
	} 
}

posted @ 2021-08-05 23:01  Chasing-Dreams  阅读(57)  评论(0)    收藏  举报