cf1110D. Jongmah

发布时间 2023-10-06 11:44:04作者: gan_coder

cf1110D. Jongmah

如果能够发现一点转化的话就简单很多
比如说最后的答案里出现了
三个(a,a+1,a+2),我们可以将它看作是(a,a,a),(a+1,a+1,a+1),(a+2,a+2,a+2)
也就是每种三元组(除了(a,a,a))最多只会出现两次
那么每种数最多有6个是个其它数组成三元组。
直接dp即可

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#define fo(i,a,b) for (int (i)=(a);(i)<=(b);(i)++)
#define fd(i,b,a) for (int (i)=(b);(i)>=(a);(i)--)
#define mk(x,y) make_pair((x),(y))
using namespace std;
typedef double db;
typedef long long ll;
const int N=1e6+5;
int c[N],r[N];
int f[N][7][7],n,m,x,ans,tot;
bool bz[N][7][7];
void cmax(int &x,int y){
	x=max(x,y);
}
int main()
{
//	freopen("data.in","r",stdin);	
	scanf("%d %d",&n,&m);
	fo(i,1,n) scanf("%d",&x), c[x]++;
	fo(i,1,m) {
		if (c[i]>=6) {
			tot+=(c[i]-6)/3;
			r[i]=(c[i]-6)%3;
			c[i]=6;
		}
	}
	
//	fo(i,1,m) printf("%d %d\n",r[i],c[i]);
	int z=0;
	bz[0][0][0]=1;
	fo(i,1,m) {
		fo(j,0,6) fo(k,0,6) { //
			if (!bz[i-1][j][k]) continue;
			fo(l,0,c[i]) {
				int d=min(l,min(j,k));
				
				if (i>=3) {
					z=(k-d+r[i-2])/3;
				}
				else z=0;
				cmax(f[i][c[i]-d][j-d], f[i-1][j][k]+d+z);
				bz[i][c[i]-d][j-d]=1;
			}
		}
	}
	
	z=0;
	fo(i,0,6) fo(j,0,6) {
		if (bz[m][i][j]) {
			z=(i+r[m])/3+(j+r[m-1])/3;
			ans=max(ans, f[m][i][j]+z);
		}
	}
	
	printf("%d",ans+tot);
	
	return 0;
}