Educational Codeforces Round 22 D. Two Melodies DP
阿新 • • 發佈:2018-12-13
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; }