求求你不要再摔馍片了
求求你不要再摔馍片了
拆成两条链,维护起始
一、问题转化
按初始顺序处理每包馍片时,每个馍片只有两种命运:
- 不扔:留在前面的部分,保持原相对顺序,组成子序列 \(A\)
- 扔到最后:按被扔的先后顺序排到后面,组成子序列 \(B\)
最终吃的顺序一定是:
\[A + B
\]
所以本质上是:把原序列划分成两个保持原序的子序列 \(A\) 和 \(B\),最后按 \(A\) 接 \(B\) 的顺序吃。
二、额外开心度的来源
额外收益只来自相邻两包馍片的味道转移:
\[\text{gain}(x,y) = (y-x+5)\bmod 5
\]
最终序列 \(A+B\) 的额外收益分三块:
- \(A\) 内部相邻转移
- \(B\) 内部相邻转移
- 跨接收益:\(A\) 的最后一包 \(\to\) \(B\) 的第一包
前两块可以在 DP 过程中边放边算,第三块等所有馍片放完后再补。
三、DP 状态
因为最终要拼成 \(A+B\),我们必须知道:
- \(A\) 的末尾(用于算 \(A\) 内部转移,也用于最后跨接到 \(B\))
- \(B\) 的开头(用于最后跨接)
- \(B\) 的末尾(用于算 \(B\) 内部转移)
所以状态设计为:
\[dp[x][y][z]
\]
- \(x\):\(A\) 链末尾味道,\(0\) 表示 \(A\) 为空
- \(y\):\(B\) 链开头味道,\(0\) 表示 \(B\) 为空
- \(z\):\(B\) 链末尾味道,\(0\) 表示 \(B\) 为空
- 值:当前累计的额外开心度(不含最后的跨接收益)
四、转移
处理当前味道为 \(m\) 的馍片时:
1. 放入 \(A\) 链末尾
- 若 \(A\) 非空,新增收益 \(\text{gain}(x,m)\)
- 新状态:\(A\) 末尾变成 \(m\)
\[dp[m][y][z] = max(dp[m][y][z], pre + gain(x, m))
\]
2. 放入 \(B\) 链末尾
- 若 \(B\) 非空,新增收益 \(\text{gain}(z,m)\)
- 若 \(B\) 原本为空,当前膜片变成 \(B\) 的开头,即 y = m
- 末尾一定变成 \(m\)
最后处理A B链连接处的收益即可
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int INF = 1e8;
int dp[6][6][6], ndp[6][6][6]; //A链以x结尾,B链以y开头,以z结尾
int gain(int a, int b) {
return (b - a + 5) % 5;
}
void solve() {
int n; cin >> n;
vector<int> a(n);
for(int i = 0; i < n; i ++) cin >> a[i];
fill(&ndp[0][0][0], &ndp[0][0][0] + 6*6*6, -INF);
ndp[0][0][0] = 0;
for(int m : a) {
fill(&dp[0][0][0], &dp[0][0][0] + 6*6*6, -INF);
for(int x = 0; x < 6; x ++) {
for(int y = 0; y < 6; y ++) {
for(int z = 0; z < 6; z ++) {
if(ndp[x][y][z] == -INF) continue;
int pre = ndp[x][y][z];
//放A
int Aadd = (x == 0 ? 0 : gain(x, m));
dp[m][y][z] = max(dp[m][y][z], pre + Aadd);
//放B
int Badd = (z == 0 ? 0 : gain(z, m));
int ny = (y == 0 ? m : y);
dp[x][ny][m] = max(dp[x][ny][m], pre + Badd);
}
}
}
swap(dp, ndp);
}
int ans = 0;
for(int x = 0; x < 6; x ++) {
for(int y = 0; y < 6; y ++) {
for(int z = 0; z < 6; z ++) {
if(ndp[x][y][z] == -INF) continue;
int res = ndp[x][y][z];
if(x != 0 && y != 0) res += gain(x, y);
ans = max(ans, res);
}
}
}
cout << ans + n << "\n";
}
int main() {
ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
int _ = 1; //cin >> _;
while(_--) solve();
return 0;
}

浙公网安备 33010602011771号