D. Geniue
Frozen_Guardian题解
Implicit_总结
首先把此序列看作一个完全图,然后按照边权从小到大的顺序枚举边。
如何按照边权从小到大枚举边?
下面考虑形如边
(
a
,
b
)
(a,b)
(a,b)都默认
a
<
b
a<b
a<b。
任意考虑两条边
(
a
,
b
)
(a,b)
(a,b)和
(
c
,
d
)
(c,d)
(c,d),不难发现只要有
b
<
d
b<d
b<d,一定有
c
a
,
b
<
c
c
,
d
c_{a,b}<c_{c,d}
ca,b<cc,d,而对于较大的点相同的情况比如
(
a
,
i
)
(a,i)
(a,i)和
(
b
,
i
)
(b,i)
(b,i),显然如果
a
<
b
a<b
a<b那么有边权
c
a
,
i
>
c
b
,
i
c_{a,i}>c_{b,i}
ca,i>cb,i。
于是如果想要从小到大枚举边权只需要从小到大枚举
i
i
i,从大到小枚举
j
j
j
设计dp:
状态表示:
f
i
f_i
fi表示以
i
i
i节点结尾时的最大值
状态转移: { f i = max { f i , f j + ∣ s i − s j ∣ } f j = max { f j , f i + ∣ s i − s j ∣ } \begin{cases}f_i=\max\{f_i,f_j+|s_i-s_j|\}\\f_j=\max\{f_j,f_i+|s_i-s_j|\}\end{cases} {fi=max{fi,fj+∣si−sj∣}fj=max{fj,fi+∣si−sj∣}
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
using ll=long long;
constexpr int N=200010;
ll dp[N],s[N],tag[N];
int n;
int main()
{
ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
int T=1;
cin>>T;
while(T--)
{
cin>>n;
for(int i=1;i<=n;i++) cin>>tag[i];
for(int i=1;i<=n;i++) cin>>s[i];
memset(dp,0,sizeof(ll)*(n+1));
// i从小打到枚举 而i相同从大到小枚举j 保证边是从小到大枚举 本质枚举边
for(int i=1;i<=n;i++)
for(int j=i-1;j>=1;j--)
if(tag[i]!=tag[j])
{
ll dpj=dp[i]+abs(s[i]-s[j]);
ll dpi=dp[j]+abs(s[i]-s[j]);
dp[i]=max(dp[i],dpi);
dp[j]=max(dp[j],dpj);
}
cout<<*max_element(dp+1,dp+1+n)<<'\n';
}
return 0;
}