【動態規劃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< y那麼由於兩個子串並沒有順序可言,相當於f[y][x]。
爲了防止交叉,我們更新f[x][y]時,只從f[i][y]( i!=y&&i<=x) ,因爲如果我們從f[x][i]( x> y) 更新的話,我們無法知道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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章