天天看點

Codeforces Global Round 1 D. Jongmah(DP)

D. Jongmah

time limit per test3 seconds

memory limit per test256 megabytes

inputstandard input

outputstandard output

You are playing a game of Jongmah. You don’t need to know the rules to solve this problem. You have n tiles in your hand. Each tile has an integer between 1 and m written on it.

To win the game, you will need to form some number of triples. Each triple consists of three tiles, such that the numbers written on the tiles are either all the same or consecutive. For example, 7,7,7 is a valid triple, and so is 12,13,14, but 2,2,3 or 2,4,6 are not. You can only use the tiles in your hand to form triples. Each tile can be used in at most one triple.

To determine how close you are to the win, you want to know the maximum number of triples you can form from the tiles in your hand.

Input

The first line contains two integers integer n and m (1≤n,m≤106) — the number of tiles in your hand and the number of tiles types.

The second line contains integers a1,a2,…,an (1≤ai≤m), where ai denotes the number written on the i-th tile.

Output

Print one integer: the maximum number of triples you can form.

Examples

inputCopy

10 6

2 3 3 3 4 4 4 5 5 6

outputCopy

3

inputCopy

12 6

1 5 3 3 3 4 3 5 3 2 3 3

outputCopy

3

inputCopy

13 5

1 1 5 1 2 3 3 2 4 2 3 4 5

outputCopy

4

Note

In the first example, we have tiles 2,3,3,3,4,4,4,5,5,6. We can form three triples in the following way: 2,3,4; 3,4,5; 4,5,6. Since there are only 10 tiles, there is no way we could form 4 triples, so the answer is 3.

In the second example, we have tiles 1, 2, 3 (7 times), 4, 5 (2 times). We can form 3 triples as follows: 1,2,3; 3,3,3; 3,4,5. One can show that forming 4 triples is not possible.

題意大概是,給你n個最大值為m的數,每次可以取三個連續的數或者三個相同的數,求能取的最大數。我一開始總覺得這個題我在哪見過,當時是個貪心,後來着手寫了之後發現不對,這個題隻能dp。

這個題dp的要點在于,取三組個相同的連續數字相當于取三組連續的相同數字,是以(n,n+1,n+2)這種,最多可以出現兩次,然後開始dp。

dp[i][j][k]代表在i這個數之前,取了j個(i-1,i,i+1)和k個(i,i+1,i+2)的情況下,最多的組數。

是以目前剩下的沒有被取完的i就應該是cnt[i]-j-k。轉移方程是dp[i + 1][k][t] = max(dp[i + 1][k][t], dp[i][j][k] + (now - t) / 3 + t);

非常巧妙,希望什麼時候我也能自己寫出來一次dp。

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#include<list>
#include<math.h>
#include<vector>
#include<stack>
#include<string>
#include<set>
#include<map>
#include<numeric>
#include<stdio.h>
#include<functional>
#include<time.h>
#pragma warning(disable:6031)

using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e6 + 10;
const ll mode = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const double pi = 3.14159265358979323846264338327950;
template <class T> inline T min(T a, T b, T c) { return min(min(a, b), c); }
template <class T> inline T max(T a, T b, T c) { return max(max(a, b), c); }
template <class T> inline T min(T a, T b, T c, T d) { return min(min(a, b), min(c, d)); }
template <class T> inline T max(T a, T b, T c, T d) { return max(max(a, b), max(c, d)); }

int cnt[maxn];
int dp[maxn][3][3];
int main()
{
	int n, m, a;
	scanf("%d %d", &n, &m);
	for (int i = 1; i <= n; i++)
	{
		scanf("%d", &a);
		cnt[a]++;
	}
	
	memset(dp, -inf, sizeof(dp));
	dp[0][0][0] = 0;

	for (int i = 0; i <= m + 1; i++)
		for (int j = 0; j < 3; j++)
			for (int k = 0; k < 3; k++) 
			{
				if (dp[i][j][k] < 0)
					continue;
				int now = cnt[i + 1] - j - k;
				for (int t = 0; t < 3 && t <= now; t++) 
					dp[i + 1][k][t] = max(dp[i + 1][k][t], dp[i][j][k] + (now - t) / 3 + t);
			}

	printf("%d\n", dp[m + 1][0][0]);


	return 0;
}
           
dp