并不对劲的loj507

传送门->

发现两次取牌取走的区间不会是相交且不包含的;先取走一段,再以这段前的牌为左端点、以这段后的牌为右端点取一次的情况,相当于只取后一次。

所以这题相当于从一列牌中取走互不相交的几段,且每段首尾的牌花色相同。

 就可以设dp[i]表示第一张牌到第i张牌的取出的和最大是多少。转移时需要枚举第1到第i-1张牌中所有与第i张牌花色相同的。

设s[i]为点数的前缀和,注意到转移是dp[i]=max(dp[j]+s[i]-s[j])=s[i]+max(dp[j]-s[j])(1<=j<i,c[j]=c[i]),所以对每种花色记(dp[j]-s[j])的最大值就行。

#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<ctime>
#include<iomanip>
#include<iostream>
#include<map>
#include<queue>
#include<stack>
#include<vector>
#define rep(i,x,y) for(register LL i=(x);i<=(y);i++)
#define dwn(i,x,y) for(register LL i=(x);i>=(y);i--)
#define maxn 1000010
#define LL long long
using namespace std;
LL read()
{
	LL x=0,f=1;char ch=getchar();
	while(!isdigit(ch)&&ch!='-')ch=getchar();
	if(ch=='-')f=-1,ch=getchar();
	while(isdigit(ch))x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	return x*f;
}
void write(LL x)
{
	LL f=0;char ch[20];
	if(!x){putchar('0'),putchar('\n');return;}
	if(x<0)x=-x,putchar('-');
	while(x)ch[++f]=x%10+'0',x/=10;
	while(f)putchar(ch[f--]);
	putchar('\n');
}
LL dp[maxn],c[maxn],v[maxn],to[maxn],s[maxn],n,k,ans;
int main()
{
	memset(to,-1,sizeof(to));
	n=read(),k=read();
	rep(i,1,n)c[i]=read();
	rep(i,1,n)v[i]=read(),s[i]=s[i-1]+v[i];
	rep(i,1,n)
	{
		dp[i]=max(dp[i],dp[i-1]);
		if(to[c[i]]==-1)to[c[i]]=i;
		else
		{
			dp[i]=max(dp[i],dp[to[c[i]]-1]-s[to[c[i]]-1]+s[i]);
			if(dp[to[c[i]]-1]-s[to[c[i]]-1]<dp[i-1]-s[i-1])to[c[i]]=i;
		}
		ans=max(ans,dp[i]);
	}
	write(ans);
	return 0;
}

  

猜你喜欢

转载自www.cnblogs.com/xzyf/p/9670912.html