LGJ的题

发布时间 2023-08-26 16:28:50作者: 傻阙的缺

题意:

\(3*n\)张卡片从左往右排成一行,第\(i\)张卡片写有一个整数\(a_i\),代表这个卡片的价值,其中\(1\leq a_i\leq n\)

重复以下操作\(n-1\)次:

\(1\)、针对当前剩下的卡片,你可以对最左边的\(5\)张卡片任意调整次序,调整结束后,若最左边的\(3\)张卡片的价值相同,那么你的得分会增加\(1\)

\(2\)、最左边的\(3\)张卡片会被删除。

若最终剩下的\(3\)张卡片的价值相同,你得分再增加\(1\)分。

输出最大总得分。


分析:

考虑\(DP\)

因为状态有\(n^2\)个,所以我们不可以枚举每个状态,而是从新加入的三个数中取改变状态

\(f_{i,j}\)表示删除之后剩下的两张牌为\(i,j\)得到的最大价值

\(p\)表示\(f\)的整个二维数组中最大的数

\(g_i\)表示\(\sum\limits_{j=1}^n max(f_{i,j})\)

不妨设加入的数为\(x,y,z\),我们分情况考虑:

\(1\)\(x=y=z\),直接令\(ans++\)即可

\(2\)\(x=y\neq z\),枚举\(i\),更新\(f_{z,i}=max(f_{z,i},max(f_{i,x}+1,g_i))\)

\(3\)\(x\neq y\neq z\),枚举\(i\),更新\(f_{z,i}=max(f_{z,i},g_i)\)

然后还要更新\(f_{x,y}=max(p,f{z,z}+1)\)同理更新\(f_{x,z},f_{y,z}\)

细节:

我们这些数是同时更新的,所以我们要先新开一个数组去记录上一步的状态,防止这一步的某个状态去影响其他状态

总结:

\(DP\)可以从改变的状态入手,假如改变的状态很少,那就枚举改变的状态,而不是枚举所有状态。

上代码:

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=2100;
ll n,a[3*N],ans;
ll f[N][N],g[N],la[N][N],p;
ll t1,t2,t3;
ll ans1;
void xg(ll x,ll y,ll z)
{
	f[x][y]=f[y][x]=max(p,la[z][z]+1);
	if(x==y)
	{
		for(ll i=1;i<=n;i++)
		{
			f[z][i]=max(f[z][i],max(la[x][i]+1,g[i]));
			f[i][z]=max(f[i][z],max(la[x][i]+1,g[i]));
		}
	}
	else
	{
		for(ll i=1;i<=n;i++)
		{
			f[z][i]=max(f[z][i],g[i]);
			f[i][z]=max(f[i][z],g[i]);
		}
	}
}
void init(ll x,ll y,ll z)
{
	p=max(p,f[x][y]);
	for(ll i=1;i<=n;i++)
	{
		g[z]=max(g[z],f[z][i]),g[i]=max(g[i],f[z][i]);
		la[z][i]=f[z][i];
		la[i][z]=f[i][z];
		p=max(p,f[z][i]);
	}
}
int main()
{
	scanf("%lld",&n);
	for(ll i=1;i<=3*n;i++)
	scanf("%lld",&a[i]);
	for(ll i=1;i<=n;i++)
	for(ll j=1;j<=n;j++)
	f[i][j]=-114514,la[i][j]=-114514;
	for(ll i=1;i<=n;i++)
	g[i]=-114514;
	f[a[1]][a[2]]=0;
	f[a[2]][a[1]]=0;
	la[a[1]][a[2]]=0;
	la[a[2]][a[1]]=0;
	g[a[1]]=0;
	g[a[2]]=0;
	for(ll i=1;i<n;i++)
	{
		t1=a[3*i],t2=a[3*i+1],t3=a[3*i+2];
		if(t1==t2&&t2==t3)
		{
			ans++;
			continue;
		}
		xg(t1,t2,t3);
		xg(t2,t3,t1);
		xg(t3,t1,t2);
		init(t1,t2,t3);
		init(t2,t3,t1);
		init(t3,t1,t2);
	}
	for(ll i=1;i<=n;i++)
	for(ll j=1;j<=n;j++)
	ans1=max(ans1,f[i][j]+(i==j&&i==a[3*n]));
	printf("%lld\n",ans+ans1);
	return 0;
}