并不对劲的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; }