2024牛客多校2I Red Playing Cards

本文同步于我的博客

Problem

There are 2n cards arranged in a row, with each card numbered from 1 to n having exactly 2 copies.

Each time, Red can choose a subarray of consecutive cards (at least 2 cards) to remove from the deck. The chosen subarray must satisfy that the first and last cards have the same number. The score for this operation is: the number of cards multiplied by the number on the first card. Now Red wants to know what is the maximum value of the final score?

给你一个长度为 2n 的数组,1n 每个数字恰好出现两次。你可以进行这样的操作:选择两个相同的数字 x (必须都还存在于数组中),将这两个数以及其间的所有数字(共计 cnt 个)全部拿走,并获得 xcnt 得分。求最终最多能够获得多少分?

1n3×103

Solution

我们发现基本有这三种情况:

  • 相离。比如1 1 3 313互不影响。
  • 包含。比如1 3 3 1,可以先拿3-3再拿1-1,也可以直接一次拿1-1,此时3没有任何贡献。
  • 相交。比如1 3 1 3,如果拿了1-1就不能再拿3-3了,拿了3-3也不能再拿1-1

f(i)[li,ri] 这段区间的最大得分。li,ri 分别指第一个 i 和第二个 i 的位置。

先假设 [li,ri] 中每个数字的贡献都是 i,而如果遇到了另一个区间 [lj,rj] 满足 (li<lj<rj<ri),那么考虑使用 f(j) 来代替这一个子区间的贡献。

这里一定有 lenj<leni,所以我们按照区间长度 leni 排序来计算 f(i)

那么如何计算 f(i) 呢?

g(k) 表示,在计算 f(i) 时,区间 [li,k] 的最大贡献。

  • 对于一般情况而言,g(k)=g(k1)+i
  • 而如果当前 k 是某个数字 j 的第二次出现的地方,且这个数字第一次出现的地方 lj[li,k],那么需要考虑有可能先抹去 j ,也就是取 [lj,rj] 得分为 f(j),会使得答案更优,。

(1)g(k)={max(g(k1)+i,g(lj1)+f(j)), if k=rj and lj>lig(k1)+i, otherwise 

而我们需要的 f(i)=g(ri)

为了得到整个数组的得分,这里有个trick。我们在数组前后添加两个0,求 f(0) 即可。

时间复杂度 O(n2)

Code

/**************************************************************
 * Problem: 
 * Author: Vanilla_chan
 * Date: 
 * E-Mail: heshaohong2015@outlook.com
 **************************************************************/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<limits.h>
#define IL inline
#define re register
#define LL long long
#define ULL unsigned long long
#ifdef TH
#define debug printf("Now is %d\n",__LINE__);
#else
#define debug
#endif
#ifdef ONLINE_JUDGE
char buf[1<<23],* p1=buf,* p2=buf,obuf[1<<23],* O=obuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
using namespace std;



#define N 6010

int n;
int a[N],l[N],r[N],len[N];
bool cmp(int x,int y)
{
	return len[x]<len[y];
}
vector<int>p;
int f[N],g[N];
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	cout.precision(10);
	int t=1;
//	cin>>t;
	while(t--)
	{
		cin>>n;
		for(int i=1;i<=n*2;i++)
		{
			cin>>a[i];
			if(l[a[i]])
			{
				r[a[i]]=i;
				len[a[i]]=i-l[a[i]]+1;
			}
			else l[a[i]]=i;
		}
		l[0]=0,r[0]=2*n+1,len[0]=2*n+2;
		for(int i=0;i<=n;i++)
		{
			p.push_back(i);
		}
		sort(p.begin(),p.end(),cmp);
//		for(int x=0;x<=n;x++) cout<<p[x]<<" "; cout<<endl;
		for(auto x:p)
		{
			for(int k=l[x];k<=r[x];k++)
			{
				g[k]=g[k-1]+x;
				int y=a[k];
				if(k==r[y]&&l[y]>l[x])
				{
					g[k]=max(g[k],g[l[y]-1]+f[y]);
				}
			}
			f[x]=g[r[x]];
			for(int k=l[x];k<=r[x];k++) g[k]=0;
//			cout<<"f["<<x<<"]="<<f[x]<<endl;
		}
		cout<<f[0]<<endl;
		
	}
	return 0;
}
posted @   Vanilla_chan  阅读(57)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示