【动态规划12】codeforces813D Two Melodies(官方题解翻译)

题目描述

Alice is a beginner composer and now she is ready to create another masterpiece. And not even the single one but two at the same time!
Alice has a sheet with n notes written on it. She wants to take two such non-empty non-intersecting subsequences that both of them form a melody and sum of their lengths is maximal.
Subsequence is a sequence that can be derived from another sequence by deleting some elements without changing the order of the remaining elements.
Subsequence forms a melody when each two adjacent notes either differs by 1 or are congruent modulo 7.
You should write a program which will calculate maximum sum of lengths of such two non-empty non-intersecting subsequences that both of them form a melody.

题目大意就是从长度为n的序列a[]中,让你取出两个非空不相交子序列,使两个子序列长度最长。
子序列满足相邻数字满足两个性质其中之一
①相差为1
②mod 7的值相同

输入输出格式

The first line contains one integer number n (2 ≤ n ≤ 5000).
The second line contains n integer numbers a1, a2, …, an (1 ≤ ai ≤ 105) — notes written on a sheet.
Print maximum sum of lengths of such two non-empty non-intersecting subsequences that both of them form a melody.

英语渣表示很绝望,看着官方题解搞了好久。
f[x][y]表示两个旋律分别以x和y结束时答案的最大值。如果x==0||y==0证明其中一个子串为空。
只维护x>y的情况,因为若x==y显然不符合题意,若x < <script type="math/tex" id="MathJax-Element-19"><</script>y那么由于两个子串并没有顺序可言,相当于f[y][x]。
为了防止交叉,我们更新f[x][y]时,只从f[i][y] ( i!=y&&i<=x),因为如果我们从f[x][i] ( x>y ) <script type="math/tex" id="MathJax-Element-24">)</script>更新的话,我们无法知道i在第一个串中有没有被取。(当时想了半天怎么判交叉..这里直接排除交叉的可能,感觉自己可能没有智商吧)

以上总结一下,说人话大概就是循环为:
    for:y=0 to n
        for:x=1 to n
            if(x==y)continue;
            solve();

为了快速更新f数组,需要额外维护两个数组。
maxmod和maxnum数组。
maxmod[j]表示的是f[1~x][y]中a[i]%7==j中f[i][y]最大的值
maxnum同理,表示的是a[i]==j中最大的值。
是不是有一种LIS的感觉?
之后就特别好搞了,分情况转移。
枚举一个新加的数字,如果和之前的数字相比
①mod 7值相同 f[x][y]=max(f[x][y],maxmod[a[x] mod 7]+1)
②大1 f[x][y]=max(f[x][y],maxnum[a[x]-1]+1)
③小1 f[x][y]=max(f[x][y],maxnum[a[x]+1]+1)
④重新找子串 f[x][y]=max(f[x][y],f[0][y]+1)
之后取所有f[x][y]中答案最大值就随便搞搞搞出来了。

#include<bits/stdc++.h>
#define fer(i,j,n) for(int i=j;i<=n;i++)
#define far(i,j,n) for(int i=j;i>=n;i--)
#define ll long long
const int maxn=5010;
const int mxan=1e5+10;
const int INF=1e9+7;
using namespace std;
/*----------------------------------------------------------------------------*/
inline int read()
{
    char ls;int x=0,sng=1;
    for(;ls<'0'||ls>'9';ls=getchar())if(ls=='-')sng=-1;
    for(;ls>='0'&&ls<='9';ls=getchar())x=x*10+ls-'0';
    return x*sng;
}
/*----------------------------------------------------------------------------*/
int n;
int a[maxn],f[maxn][maxn],ans=-1;
int maxnum[mxan],maxmod[7];
void init()
{
    memset(maxnum,0,sizeof(maxnum));
    memset(maxmod,0,sizeof(maxmod));
}
int main()
{
    n=read();
    fer(i,1,n)a[i]=read();
    fer(y,0,n)
    {
        init();
        fer(x,1,n)
        {
            if(x==y)continue;
            if(y>x)
            {
                maxnum[a[x]]=max(maxnum[a[x]],f[x][y]);
                maxmod[a[x]%7]=max(maxmod[a[x]%7],f[x][y]);
                continue;
            }
            f[x][y]=max(f[x][y],maxmod[a[x]%7]+1);
            f[x][y]=max(f[x][y],maxnum[a[x]-1]+1);
            f[x][y]=max(f[x][y],maxnum[a[x]+1]+1);
            f[x][y]=max(f[x][y],f[0][y]+1);
            f[y][x]=f[x][y];
            maxmod[a[x]%7]=max(maxmod[a[x]%7],f[x][y]);
            maxnum[a[x]]=max(maxnum[a[x]],f[x][y]);
            ans=max(ans,f[x][y]);
        }
    }
    cout<<ans;
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值