1 条题解
-
0
自动搬运
来自洛谷,原作者为

ZHR100102
kipfel 可爱喵搬运于
2025-08-24 23:09:48,当前版本为作者最后更新于2025-05-04 13:50:33,作者可能在搬运后再次修改,您可在原文处查看最新版自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多
以下是正文
质量还行的线段树优化 DP。
手膜样例不难发现,一张牌在和另一张牌匹配后,中间不能再有匹配的牌了,因为这样会把前一个匹配的牌挤出左手。同时因为只有两只手,所以不能同时匹配三张及以上的牌。
因此对于任意两对匹配的牌,只可能有两种关系:
- 相交关系。且一对匹配的牌最多只能和另一对匹配的牌相交。
- 不交关系。
于是设计 DP: 表示考虑前 位的最大答案。为了方便统计答案,我们强制匹配牌的贡献在右端点计算;与另一对牌相交的,以靠右的一对牌为准。那么有三类转移:
- 继承状态:。
- 与其他对匹配的牌不交的转移:。
- 与某一对牌相交的转移:。其中 是某一对经过了 的牌,即 。
其中, 表示第一个 的位置。
前两种转移是容易的,考虑如何优化第三种转移。发现把有关 的变量提出来,是不含其它变量的,而对于有关 的两个不等限制,可以用一个类似二维数点的东西解决。但是我不会二维数点!
正着不好做,于是考虑反向计算,让每个 给会贡献到的 做贡献。发现只要 的时候贡献就能被计算,因此维护一个求区间 ,单点查的线段树,算贡献的时候把 区间贡献一个 即可。
时间复杂度 。
#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
- 上传者