Solution
设 \(f_{i,j,k}\) 表示考虑取值为 \(1\sim i\) 的牌,出现了 \(j\) 个 \([i-1,i,i+1]\),\(k\) 个 \([i,i+1,i+2]\)。
注意到 \(3\) 个 \([x-1,x,x+1]\) 能替换成 \([x-1,x-1,x-1],[x,x,x],[x+1,x+1,x+1]\),所以 \(f_{i,j,k}\) 中 \(0\le j,k\le 2\)。
转移的时候枚举 \(0\le l\le 2\),然后考虑 \(f_{i-1,l,j}\) 怎么转移到 \(f_{i,j,k}\):
红色的方框就是 \(f_{i,j,k}\) 比 \(f_{i-1,l,j}\) 多出来的部分,那么:
\[f_{i,j,k}=\max_{l=0}^2\left\{f_{i-1,l,j}+k+\left\lfloor\frac{cnt_i-j-k-l}3\right\rfloor\right\}
\]
Code
#include<cstdio>
#include<algorithm>
const int N=1e6;
int n,m,cnt[N+10],f[N+10][3][3];
int main(){
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++){
int x;scanf("%d",&x);
cnt[x]++;
}
for(int i=1;i<=m;i++)
for(int j=0;j<=2;j++)
for(int k=0;k<=2;k++)
for(int l=0;l<=2;l++)
if(cnt[i]>=j+k+l)
f[i][j][k]=std::max(f[i][j][k],f[i-1][l][j]+(cnt[i]-j-k-l)/3+k);
printf("%d\n",f[m][0][0]);
return 0;
}