I Red Playing Cards

链接:登录—专业IT笔试面试备考平台_牛客网
来源:牛客网
 

题目描述

There are 2⋅n2\cdot n2⋅n cards arranged in a row, with each card numbered from 111 to nnn having exactly 222 copies.

Each time, Red can choose a subarray of consecutive cards (at least 222 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?

输入描述:

The first line contains a positive integer n(1≤n≤3×103)n(1\leq n \leq 3\times 10^3)n(1≤n≤3×103) — the number of card types.

The second line contains 2⋅n2\cdot n2⋅n positive integers ai(1≤ai≤n)a_i(1\leq a_i \leq n)ai​(1≤ai​≤n) — the number on each card from left to right.

输出描述:

A single positive integer — representing the maximum final score.

示例1

输入

复制4 4 4 1 2 3 1 3 2

4
4 4 1 2 3 1 3 2

输出

复制21

21

说明

First operation: choose the 555-th to 777-th cards, get 999 points, and the remaining cards are [4,4,1,2,2][4,4,1,2,2][4,4,1,2,2].

Second operation: from the remaining cards, choose the 111-st to 222-nd cards, get 888 points, and the remaining cards are [1,2,2][1,2,2][1,2,2].

Third operation: from the remaining cards, choose the 222-nd to 333-rd cards, get 444 points, and there is still 111 card remaining, so no more operations can be performed.

这题有点区间dp的意思,题目中一段要乘上区间,我们可以用累加来替代,在数组中选择相同的数字为一段区间得到分数,得分为数字乘以一段的数量也就是说在合并区间时要先合并小区间,再将上一段区间最优解继承,由于我们再dp一段区间时有区间交错(类似于1313这种情况),还有小块区间在大块区间里面(3113)因此我们上段区间的最优解要另开一个ans数组,所以我们可以得出状态转移方程为错开的区间中用代码块中第一行在合并时遵循一个原则,小区间先并。听完题集主打一个感觉很ez呀!!!

//dp【x】=max(dp[x-1]+i,dp[l[x]-1]+ans[s[x]]) 
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define IOS ios::sync_with_stdio(false);
#define fir first
#define sec second
#define pii pair<int,int>
#define pb push_back
const int N=6e5+5,inf=0x3f3f3f3f3f3f3f3f;
int n;
int dir[8][2]= {0,1,0,-1,1,0,-1,0,1,1,1,-1,-1,1,-1,-1};
int s[N],l[N],r[N],w[N],dp[N]/*删到x位置的得分*/,ans[N]/*区间最大得分*/;
bool cmp(int a,int b) {
	return r[a]-l[a]<r[b]-l[b];
}
int upd(int x,int y,int c) {
	memset(dp,0,sizeof dp);
	for(int i=x; i<=y; i++) {
		if(l[s[i]]==i) {
//			cout<<i<<endl;
			dp[r[s[i]]]=max(dp[r[s[i]]],ans[s[i]]+dp[l[s[i]]-1]);
		}
		dp[i]=max(dp[i],dp[i-1]+c);
//		for(int j=1; j<=2*n; j++) {
//			cout<<dp[j]<<" ";
//		}
//		cout<<endl;
	}
	return dp[y];
}
signed main() {
	cin>>n;
	for(int i=1; i<=n*2; i++) {
		cin>>s[i];
		r[s[i]]=i;//每张牌右端点位置
	}
	for(int i=2*n; i>=1; i--)l[s[i]]=i; //每张牌左端点位置
	for(int i=1; i<=n; i++)w[i]=i; //先从小区间合并
	sort(w+1,w+n+1,cmp);//小区间排序
	for(int i=1; i<=n; i++)ans[w[i]]=upd(l[w[i]],r[w[i]],w[i]); //dp答案
	cout<<upd(1,2*n,0)<<endl;
	return 0;
}

  • 15
    点赞
  • 18
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值