Duizi and Shunzi
Time Limit: 6000/3000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 357 Accepted Submission(s): 179
Problem Description
Nike likes playing cards and makes a problem of it.
Now give you n integers, ai(1≤i≤n)
We define two identical numbers (eg: 2,2 ) a Duizi,
and three consecutive positive integers (eg: 2,3,4 ) a Shunzi.
Now you want to use these integers to form Shunzi and Duizi as many as possible.
Let s be the total number of the Shunzi and the Duizi you formed.
Try to calculate max(s) .
Each number can be used only once.
Now give you n integers, ai(1≤i≤n)
We define two identical numbers (eg: 2,2 ) a Duizi,
and three consecutive positive integers (eg: 2,3,4 ) a Shunzi.
Now you want to use these integers to form Shunzi and Duizi as many as possible.
Let s be the total number of the Shunzi and the Duizi you formed.
Try to calculate max(s) .
Each number can be used only once.
Input
The input contains several test cases.
For each test case, the first line contains one integer n( 1≤n≤106 ).
Then the next line contains n space-separated integers ai ( 1≤ai≤n )
For each test case, the first line contains one integer n( 1≤n≤106 ).
Then the next line contains n space-separated integers ai ( 1≤ai≤n )
Output
For each test case, output the answer in a line.
Sample Input
7 1 2 3 4 5 6 7 9 1 1 1 2 2 2 3 3 3 6 2 2 3 3 3 3 6 1 2 3 3 4 5
Sample Output
2 4 3 2HintCase 1(1,2,3)(4,5,6) Case 2(1,2,3)(1,1)(2,2)(3,3) Case 3(2,2)(3,3)(3,3) Case 4(1,2,3)(3,4,5)
题目大意:
给出N张牌,连续的三个数字的三张牌可以组成顺子,相同的两个数字组成对子。
问我们最多可以组成多少顺子和对子。
思路:
赛后百度了一波题解,发现大家都会贪心啊TAT:
①首先我们通过简单分析可以得到结论,如果三个连续的数字如果出现了多次。(222333444),我们一定是要先将其选对子,然后去选顺子。那么直接按照对子先选的顺序去贪心可以吗?显然是不行的,比如1 2 3 3 4 5这种,最优解是2,先选对子答案是1.
②那么如果满足上述条件的话,我们不难分析出,如果我们先将这些连续的出现多次的数先取了对子之后,每个数字作为一个顺子的部分的机会是很少的。我们通过简单分析得知,出现了4次就相当多了,反而多出现的顺子部分肯定要作为对子,所以4次肯定是一个可取的极限高度。
③那么我们设定Dp【i】【j】,表示我们以数字i结尾,并且以数字i结尾出现的顺子个数为j个的最优解。这里j最大取4~5其实就足够了。
那么其状态转移我们分成两种情况去走,一种是有重叠部分的去转移,一种是没有重叠部分去转移:
过程维护一下最优解即可,即ans=max(dp【i】【j】);
时间复杂度O(n*4*4)
Ac代码:
#include <bits/stdc++.h>
typedef long long int LL;
int dp[1050000][5];
int have[1050000];
int max(int x,int y)
{
if(x>y)return x;
else return y;
}
int main()
{
int n;
while(~scanf("%d",&n))
{
memset(dp,0,sizeof(dp));
memset(have,0,sizeof(have));
for(int i=1;i<=n;i++)
{
int x;scanf("%d",&x);
have[x]++;
}
int ans=0;
for(int i=1;i<=n;i++)
{
for(int j=0;j<=4;j++)
{
for(int k=0;k<=4;k++)
{
if(j==0)
dp[i][j]=max(dp[i][j],dp[i-1][k]+have[i]/2);
else
{
if(i-3>=0&&have[i]>=j&&have[i-1]>=j&&have[i-2]>=j)
{
dp[i][j]=max(dp[i][j],dp[i-3][k]+j+(have[i]-j)/2+(have[i-1]-j)/2+(have[i-2]-j)/2);
}
if(i-5>=0&&have[i]>=j&&have[i-1]>=j&&have[i-2]-k>=j)
{
dp[i][j]=max(dp[i][j],dp[i-2][k]+j-(have[i-2]-k)/2+(have[i]-j)/2+(have[i-1]-j)/2+(have[i-2]-j-k)/2);
}
}
}
ans=max(ans,dp[i][j]);
}
}
printf("%d\n",ans);
}
}