【DP 优化】【分类讨论】[ABC176F] Brave CHAIN
从没见过,被暴打了。
很容易打一个暴力。 表示取到第 i 次的时候,留下的两个值是 。
这样复杂度是 。
以下将五个值分别说成 。对于每次询问, 是确定的。 考虑优化。观察式子,总共三种情况:
- 在 中全取。如果它们不相等,对于 根本没影响。如果相等,所有状态全部 ,其实也相当于没影响。后面的情况都不用讨论了,因为一定不更优。
- 取两个。令 ,更新的是 。只用枚举 ,因为 就是 。如果不强制 相等,那相当于 中取最大值。预处理即可。
- 取一个。令 ,那就一种情况。如果不强制相等,那相当于 取最大值,同样预处理。
这样一来,我们的复杂度变为 。所谓 不适用,因为一次可以处理很多种状态。这也启示我不能被所谓的传统思路限制了思维。
实现参考了 luogu 题解,挺好的。
关于实现,注意只讨论了枚举 的情况,要时刻注意 ,还要注意状态是否合法,比如开始的两个值是 ,则 就不合法。
/*
- 别摆了
- By yfz
*/
#pragma GCC optimize(3,"Ofast","inline")
#include<bits/stdc++.h>
using namespace std;
const int N = 2e3+10;
int f[N][N]; int p[N*3],n,mf[N];
struct D{
int x,y,z;
};
int main() {
for(auto c: {1, -1}) cout << c << endl;
cin>>n;
for(int i=1;i<=3*n;i++) cin>>p[i];
memset(f,-0x3f,sizeof f); f[p[1]][p[2]] = f[p[2]][p[1]] = 0;
memset(mf,-0x3f,sizeof mf); mf[p[1]] = mf[p[2]] = 0;
int All_Plus = 0;
queue<D>q;
int ma = 0;
for(int i=5;i<=3*n;i+=3) {
int c = p[i-2], d = p[i-1], e = p[i];
// 三个都选
if(c == d && d == e) {All_Plus ++;continue;}
// 选两个
for(int a=1;a<=n;a++) q.push({a,e,mf[a]}), q.push({a,d,mf[a]}), q.push({a,c,mf[a]});
if(c == d) {
for(int a=1;a<=n;a++) q.push({a,e, f[a][c] + 1});
}
if(c == e) {
for(int a=1;a<=n;a++) q.push({a,d, f[a][c] + 1});
}
if(d == e) {
for(int a=1;a<=n;a++) q.push({a,c, f[a][d] + 1});
}
// 选一个
q.push({c,d, f[e][e] + 1});
q.push({c,e, f[d][d] + 1});
q.push({d,e, f[c][c] + 1});
q.push({c,d, ma});
q.push({c,e, ma});
q.push({d,e, ma});
while(!q.empty()) {
auto [A,B,w] = q.front(); q.pop();
ma = max(ma, f[B][A] = f[A][B] = max(f[A][B], w));
mf[A] = max(mf[A],w); mf[B] = max(mf[B],w);
}
}
int ans = 0;
for(int i=1;i<=n;i++) {
for(int j=1;j<=n;j++) ans = max(ans,f[i][j] + (i == j && j == p[3*n]));
}
cout << ans + All_Plus;
return 0;
}