1 条题解

  • 0
    @ 2025-8-24 23:09:48

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar ZHR100102
    kipfel 可爱喵

    搬运于2025-08-24 23:09:48,当前版本为作者最后更新于2025-05-04 13:50:33,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


    质量还行的线段树优化 DP。

    手膜样例不难发现,一张牌在和另一张牌匹配后,中间不能再有匹配的牌了,因为这样会把前一个匹配的牌挤出左手。同时因为只有两只手,所以不能同时匹配三张及以上的牌

    因此对于任意两对匹配的牌,只可能有两种关系:

    • 相交关系。且一对匹配的牌最多只能和另一对匹配的牌相交
    • 不交关系。

    于是设计 DP:dpidp_i 表示考虑前 ii 位的最大答案。为了方便统计答案,我们强制匹配牌的贡献在右端点计算;与另一对牌相交的,以靠右的一对牌为准。那么有三类转移:

    • 继承状态:dpi=max(dpi,dpi1)dp_i=\max(dp_i,dp_{i-1})
    • 与其他对匹配的牌不交的转移:dpi=max(dpi,dppreai+Vai)dp_i=\max(dp_i,dp_{pre_{a_i}}+V_{a_{i}})
    • 与某一对牌相交的转移:dpi=max(dpi,dppreak+Vak+Vai)dp_i =\max(dp_i,dp_{pre_{a_k}}+V_{a_k}+V_{a_i})。其中 aka_k 是某一对经过了 preaipre_{a_i} 的牌,即 preak<preai<k<ipre_{a_k}<pre_{a_i}<k <i

    其中,prexpre_x 表示第一个 xx 的位置。

    前两种转移是容易的,考虑如何优化第三种转移。发现把有关 kk 的变量提出来,是不含其它变量的,而对于有关 kk 的两个不等限制,可以用一个类似二维数点的东西解决。但是我不会二维数点!

    正着不好做,于是考虑反向计算,让每个 kk 给会贡献到的 preaipre_{a_i} 做贡献。发现只要 preak<preai<kpre_{a_k} <pre_{a_i}<k 的时候贡献就能被计算,因此维护一个求区间 max\max,单点查的线段树,算贡献的时候把 [preak,k][pre_{a_k},k] 区间贡献一个 dppreak+Vkdp_{pre_{a_k}}+V_k 即可。

    时间复杂度 O(nlogn)O(n \log n)

    #include <bits/stdc++.h>
    #define lc (p<<1)
    #define rc ((p<<1)|1)
    using namespace std;
    typedef long long ll;
    const int N=1000005;
    const ll inf=0x3f3f3f3f3f3f3f3f;
    ll n,a[N],b[N],dp[N],pre[N];
    struct Node{
    	int l,r;
    	ll v,tag;
    };
    struct Segtree{
    	Node tr[4*N];
    	void pushup(int p)
    	{
    		tr[p].v=max(tr[lc].v,tr[rc].v);
    	}
    	void pushdown(int p)
    	{
    		if(tr[p].tag!=-inf)
    		{
    			tr[lc].tag=max(tr[lc].tag,tr[p].tag);
    			tr[lc].v=max(tr[lc].v,tr[p].tag);
    			tr[rc].tag=max(tr[rc].tag,tr[p].tag);
    			tr[rc].v=max(tr[rc].v,tr[p].tag);			
    		}
    		tr[p].tag=-inf;
    	}
    	void build(int p,int ln,int rn)
    	{
    		tr[p]={ln,rn,-inf,-inf};
    		if(ln==rn)return;
    		int mid=(ln+rn)>>1;
    		build(lc,ln,mid);
    		build(rc,mid+1,rn);
    		pushup(p);
    	}
    	void update(int p,int ln,int rn,ll x)
    	{
    		if(ln<=tr[p].l&&tr[p].r<=rn)
    		{
    			tr[p].v=max(tr[p].v,x);
    			tr[p].tag=max(tr[p].tag,x);
    			return;
    		}
    		pushdown(p);
    		int mid=(tr[p].l+tr[p].r)>>1;
    		if(ln<=mid)update(lc,ln,rn,x);
    		if(rn>=mid+1)update(rc,ln,rn,x);
    		pushup(p);
    	}
    	ll query(int p,int x)
    	{
    		if(tr[p].l==x&&tr[p].r==x)return tr[p].v;
    		pushdown(p);
    		int mid=(tr[p].l+tr[p].r)>>1;
    		if(x<=mid)return query(lc,x);
    		else return query(rc,x);
    	}
    }tr1;
    int main()
    {
    //	freopen("smash.in","r",stdin);
    //	freopen("smash.out","w",stdout);
    	ios::sync_with_stdio(0);
    	cin.tie(0);
    	cout.tie(0);
    	cin>>n;
    	for(int i=1;i<=2*n;i++)cin>>a[i];
    	for(int i=1;i<=n;i++)cin>>b[i];
    	memset(dp,-0x3f,sizeof(dp));
    	dp[0]=0;
    	tr1.build(1,1,2*n);
    	for(int i=1;i<=2*n;i++)
    	{
    		dp[i]=max(dp[i],dp[i-1]);
    		if(pre[a[i]])
    		{
    			dp[i]=max(dp[i],tr1.query(1,int(pre[a[i]]))+b[a[i]]);
    			dp[i]=max(dp[i],dp[pre[a[i]]]+b[a[i]]);
    			tr1.update(1,pre[a[i]],i,dp[pre[a[i]]]+b[a[i]]);
    		}
    		pre[a[i]]=i;
    	}
    	cout<<dp[2*n];
    	return 0;
    }
    
    • 1

    信息

    ID
    11414
    时间
    1000ms
    内存
    1024MiB
    难度
    5
    标签
    递交数
    0
    已通过
    0
    上传者