codeforces1497 D. Geniue(dp+图论)

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+sisj}fj=max{fj,fi+sisj}

#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;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值