ABC176F Brave CHAIN题解
ABC176F Brave CHAIN题解
Link
很好的一道题。
首先考虑扔三张留两张相当于有一个大小为
考虑dp。设
首先有
首先发现若当前三张
然后发现除了上一种情况,与
这启发我们找只与
对于
若有两个数字
然后是一般的没有贡献的状态更新,容易发现只会跟
这两个都是
细节的,第一种是查询列最大值,第二种是查询全局最大值以及列最大值。
像背包一样压掉一维,这样才能保证不会被转移的状态不会占用复杂度。
由于两种转移可能同时发生,所以用 vector 来转移。
code
const int N=2e3+5;
int f[N][N];
int mx[N];//行/列最大值,这里这个矩阵是沿对角线对称的
int t[N*3];
struct hhh{
int u,v,w;
};
vector<hhh>_new;
void clr(vector<hhh>&vec){
vector<hhh>c;
swap(c,vec);
}
signed main(){
int n=read();
for(int i=1;i<=3*n;i++)
t[i]=read();
memset(f,-0x3f,sizeof(f));
memset(mx,-0x3f,sizeof(mx));
mx[t[1]]=mx[t[2]]=0;
f[t[1]][t[2]]=f[t[2]][t[1]]=0;
int d=0;
for(int i=3;i<3*n;i+=3){
int a=t[i],b=t[i+1],c=t[i+2];
if(a==b&&b==c)
d++;//全局加
else{
int mxx=-inf;
for(int j=1;j<=n;j++){
_new.pb({j,a,mx[j]});
_new.pb({j,b,mx[j]});
_new.pb({j,c,mx[j]});
mxx=max(mxx,mx[j]);
}
_new.pb({a,b,max(mxx,f[c][c]+1)});
_new.pb({b,c,max(mxx,f[a][a]+1)});
_new.pb({a,c,max(mxx,f[b][b]+1)});//以上是第二种转移
if(a==b||a==c||b==c){//第一种转移
if(b==c)
swap(a,b);
if(a==c)
swap(b,c);
for(int j=1;j<=n;j++)
_new.pb({j,c,f[a][j]+1});
}
for(hhh x:_new){
f[x.u][x.v]=f[x.v][x.u]=max(f[x.u][x.v],x.w);
mx[x.u]=max(mx[x.u],x.w);
mx[x.v]=max(mx[x.v],x.w);
}
clr(_new);
}
}
int ans=f[t[3*n]][t[3*n]]+1;//最后两个可能会再造成一次贡献
for(int i=1;i<=n;i++)
ans=max(ans,mx[i]);
print(ans+d),pc('\n');
return 0;
}