1. 程式人生 > >Educational Codeforces Round 22 D. Two Melodies DP

Educational Codeforces Round 22 D. Two Melodies DP

Description 給出長度為n的序列,從中找出2個子序列,滿足每個子序列相鄰兩數之間要麼相差1,要麼同餘於7,求這兩個子序列的最長長度和。

Sample Input 4 1 2 4 5

Sample Output 4

設f[i][j]為以i,j為結尾的子序列的最大值。 維護一個維護兩個最大值,優化轉移即可。 為了避免重複,轉移時考慮滿足i < j。

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;
typedef long long LL;
int _min(int x, int y) {return x < y ? x : y;}
int _max(int x, int y) {return x > y ? x : y;}
int read() {
	int s = 0, f = 1; char ch = getchar();
	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = getchar();
	return s * f;
}

int a[5100], b[5100], c[5100], Next[5100], Prev[5100];
int f[5100][5100];
int p[7], kk[5100];

int main() {
	int n = read();
	for(int i = 1; i <= n; i++) a[i] = read(), b[i] = a[i];
	sort(b + 1, b + n + 1); int u = 0;
	for(int i = 1; i <= n; i++) if(b[i] != b[i - 1]) b[++u] = b[i];
	for(int i = 1; i <= n; i++) c[i] = lower_bound(b + 1, b + u + 1, a[i]) - b;
	for(int i = 1; i <= u; i++) {
		if(i > 1 && b[i] == b[i - 1] + 1) Prev[i] = i - 1;
		if(i < u && b[i] + 1 == b[i + 1]) Next[i] = i + 1;
	}
	int ans = 0, po;
	for(int i = 0; i < n; i++) {
		memset(p, 0, sizeof(p)), memset(kk, 0, sizeof(kk));
		for(int j = 0; j < i; j++) p[a[j] % 7] = _max(p[a[j] % 7], f[j][i]), kk[c[j]] = _max(kk[c[j]], f[j][i]);
		for(int j = i + 1; j <= n; j++) {
			f[i][j] = f[0][i] + 1;
			f[i][j] = _max(f[i][j], p[a[j] % 7] + 1);
			f[i][j] = _max(f[i][j], _max(kk[Next[c[j]]], kk[Prev[c[j]]]) + 1);
			p[a[j] % 7] = _max(p[a[j] % 7], f[i][j]);
			kk[c[j]] = _max(kk[c[j]], f[i][j]);	
			if(f[i][j] > ans) ans = f[i][j], po = j;
		}
	} printf("%d\n", ans);
	return 0;
}