# Codeforces 813D Two Melodies（维护转移来源的DP）

D. Two Melodies
time limit per test2 seconds
memory limit per test256 megabytes
inputstandard input
outputstandard output
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.

Input
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.

Output
Print maximum sum of lengths of such two non-empty non-intersecting subsequences that both of them form a melody.

Examples
input
4
1 2 4 5
output
4
input
6
62 22 60 61 48 49
output
5
Note
In the first example subsequences [1, 2] and [4, 5] give length 4 in total.

In the second example subsequences [62, 48, 49] and [60, 61] give length 5 in total. If you choose subsequence [62, 61] in the first place then the second melody will have maximum length 2, that gives the result of 4, which is not maximal.

### 题目大意

有一个长度为N(2N5000)$N(2 \leq N \leq 5000)$的序列，要求从中选择两个相互独立的子序列，每个子序列相邻元素之间差1$1$或对于7$7$同余，使得这两个字序列的长度之和最大。

### 解题思路

首先很容易相当dp[i][j]$dp[i][j]$表示两个字序列分别以i,j$i, j$结尾的最长长度。转移就是枚举下一个位置，总时间复杂度为O(N3)$O(N^3)$，显然无法通过。
考虑固定一个i$i$，则对每个j$j$来说，只要考虑dp[i][k](k<j)$dp[i][k](k 中同余的长度最大的，值小1$1$的长度最大的，值大1$1$的长度最大的。所以我我们可以对于每个i$i$，维护每个同余值的长度最大值，和每个值的长度最大值，并在转移的过程中更新，O(1)$O(1)$的实现转移。总时间复杂度O(N2)$O(N^2)$

### AC代码

#include <iostream>
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
#include <queue>
#include <stack>
#include <cstdlib>
#include <cmath>
#include <map>
using namespace std;
#define mem(a,b) memset((a),(b),sizeof(a))

const int MAXN=5000+3;
const int MAXA=100000+3;
int N, a[MAXN];
int dp[MAXN][MAXN];//表示一个序列以i结尾，一个序列以j结尾的最大长度
int max_mod[10], max_a[MAXA];//表示此时a[j]%7为各个值的最长序列，表示a[j]为各个值的最长序列

int main()
{
scanf("%d", &N);
for(int i=1;i<=N;++i)
scanf("%d", &a[i]);
int ans=0;
for(int i=0;i<=N;++i)
{
for(int j=0;j<7;++j)
max_mod[j]=0;
for(int j=1;j<=N;++j)
max_a[a[j]]=0;
for(int j=1;j<i;++j)//预处理出此时各个情况的最大长度
{
max_mod[a[j]%7]=max(max_mod[a[j]%7], dp[i][j]);
max_a[a[j]]=max(max_a[a[j]], dp[i][j]);
}
for(int j=i+1;j<=N;++j)//进行转移并更新维护的值
{
dp[i][j]=max(max(max_a[a[j]-1], max_a[a[j]+1]), max(max_mod[a[j]%7], dp[i][0]))+1;
dp[j][i]=dp[i][j];
max_mod[a[j]%7]=max(max_mod[a[j]%7], dp[i][j]);
max_a[a[j]]=max(max_a[a[j]], dp[i][j]);
ans=max(ans, dp[i][j]);
}

}
printf("%d\n", ans);

return 0;
}