hdu6188 Duizi and Shunzi (贪心或者dp)

题意

有n张牌,第i张牌上的数字是a[i]。我们定义 两张数字是一样的牌 为对子。我们定义 三张数字连续的牌 为顺子。我们想把这n张牌组成尽可能多的顺子和对子。请计算并输出能组成的最多的顺子和对子的数量。

分析

我是傻逼我是傻逼我是傻逼!重要的事情说三遍!!

这是一道贪心,而且是并不是很复杂的贪心,但是我在场上坚定的认为他是个dp然后连写带调两个小时才过掉它!

结束后我在网上查了一下,果然只有我这么傻逼,但是我还是想把这个奇怪的dp思路写下来···

我们定义f[i]为前i张牌中对子和顺子最多的数量,sum[i]为前i张牌里面和牌i相同的牌的数量(因为是排过序的,所以一定是i前面连续的几张)

如果i和前面和i相同的几张牌全部组成对子,那么f[i]=f[i-sum[i]]+sum[i]/2;

如果i和前面和i相同的几张牌想拿出一部分来和前面的组成顺子,剩下的组成对子,那么

f[i]=max(f[i],j+(sum[i]-j)/2+f[i-sum[i]-sum[i-sum[i]]-j]+(sum[i-sum[i]]-j)/2);其中j是想用来组成的顺子数。

真鸡儿麻烦哇!!!

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <iostream>
 5
 6 using namespace std;
 7 const int maxn=1000000+10;
 8 const int INF=2147000000;
 9
10 int n;
11 long long a[maxn];
12 long long f[maxn];
13 long long sum[maxn];
14 int main(){
15     while(scanf("%d",&n)!=EOF){
16         memset(f,0,sizeof(f));
17         for(int i=1;i<=n;i++)
18             scanf("%lld",&a[i]);
19         sort(a+1,a+1+n);
20         memset(sum,0,sizeof(sum));
21         for(int i=1;i<=n;i++){
22             if(a[i]!=a[i-1])
23                 sum[i]=1;
24             else
25                 sum[i]=sum[i-1]+1;
26         }
27         f[1]=f[0]=0;
28         if(sum[2]>=2)f[2]=1;
29         else f[2]=0;
30         for(int i=3;i<=n;i++){
31            // f[i]=f[i-1];
32             int M;
33             f[i]=f[i-sum[i]]+sum[i]/2;
34
35             if(i-sum[i]>=1&&i-sum[i]-sum[i-sum[i]-sum[i-sum[i]]]>=1){
36               if(a[i]==a[i-sum[i]]+1&&a[i]==a[i-sum[i]-sum[i-sum[i]]]+2)
37               M=min(min(sum[i-sum[i]],sum[i-sum[i]-sum[i-sum[i]]]),sum[i]);
38               else M=0;
39              // cout<<i<<" "<<M<<endl;
40          //    f[i]=f[i-sum[i]]+sum[i]/2;
41               //cout<<i<<" "<<M<<endl;
42             //  cout<<i<<" "<<M<<endl;
43               for(int j=1;j<=M;j++){
44                 //f[i]=max(f[i],j+(sum[i]-j)/2+f[i-sum[i]-sum[i-sum[i]-sum[i-sum[i]]]]+(sum[i-sum[i]]-j)/2);
45                   //f[i]=max(f[i],j+f[i-sum[i]-sum[i-sum[i]-sum[i-sum[i]]]]);
46                   f[i]=max(f[i],j+(sum[i]-j)/2+f[i-sum[i]-sum[i-sum[i]]-j]+(sum[i-sum[i]]-j)/2);
47               }
48             }
49         }
50         printf("%lld\n",f[n]);
51        /*for(int i=1;i<=n;i++){
52             printf("%d %d\n",i,f[i]);
53         }*/
54         //printf("%d %d",(sum[6-sum[6]]-1)/2,f[(6-sum[6]-sum[6-sum[6]-sum[6-sum[6]]])]+1);
55     }
56
57 return 0;
58 }

如果有谁也是这么做的一定要告诉我···难道只有我这么想吗··难受··

原文地址:https://www.cnblogs.com/LQLlulu/p/8850260.html

时间: 2024-10-10 22:30:53

hdu6188 Duizi and Shunzi (贪心或者dp)的相关文章

【bzoj4922】[Lydsy六月月赛]Karp-de-Chant Number 贪心+背包dp

题目描述 给出 $n$ 个括号序列,从中选出任意个并将它们按照任意顺序连接起来,求以这种方式得到匹配括号序列的最大长度. 输入 第一行包含一个正整数n(1<=n<=300),表示括号序列的个数. 接下来n行,每行一个长度在[1,300]之间的括号序列,仅由小括号构成. 输出 输出一行一个整数,即最大长度,注意你可以一个序列也不选,此时长度为0. 样例输入 3 ()) ((() )() 样例输出 10 题解 贪心+背包dp 首先对于一个括号序列,有用的只有:长度.消耗'('的数目.以及'('减去

bzoj 1907: 树的路径覆盖【贪心+树形dp】

我是在在做网络流最小路径覆盖的时候找到这道题的 然后发现是个贪心+树形dp \( f[i] \)表示在\( i \)为根的子树中最少有几条链,\( v[i] \) 表示在\( i \)为根的子树中\( i \) 是( 0)否(1)为一条链的端点 然后贪心转移即可(有链端点则连起来) #include<iostream> #include<cstdio> #include<cstring> using namespace std; const int N=10005; i

Educational Codeforces Round 19 B. Odd sum(贪心或dp)

题意:给出一组数,从中拿出几个,要让它们之和最大并且为奇数. 这道题给出的n不大,贪心暴力一下就可以了.(-?-;) 1.贪心 我是先把数据大于0并且为偶数的数都先加起来(保证开始的sum是偶数),数据大于0且为奇数的存在a数组里,数据小于0的存在b数组里. 然后如果有a数组有奇数个,直接加起来输出就好了.奇*奇=奇 偶数个的话就从sum中拿出a1,b1.特判一下a1(a数组里面最小的那个)和b1(b数组里最大的那个)哪个的绝对值大. a1<b1 直接输出之前的sum,a1>=b1则输出sum

Yogurt factory(POJ 2393 贪心 or DP)

Yogurt factory Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 8205   Accepted: 4197 Description The cows have purchased a yogurt factory that makes world-famous Yucky Yogurt. Over the next N (1 <= N <= 10,000) weeks, the price of milk

poj -1065 Wooden Sticks (贪心or dp)

http://poj.org/problem?id=1065 题意比较简单,有n跟木棍,事先知道每根木棍的长度和宽度,这些木棍需要送去加工,第一根木棍需要一分钟的生产时间,如果当前木棍的长度跟宽度 都大于前一根木棍,那么这根木棍不需要生产时间,问你最少的生产时间是多少? 首先可以贪心,先按长度 l排序,如果l相同,按宽度w排序. 从i=0开始,每次把接下来的i+1  -  n-1 的没有标记并且长度和宽度大于等于i这根木棍的长度和宽度标记起来. 1 #include<cstdio> 2 #in

bzoj1124[POI2008]枪战maf tarjan+树规+贪心/线性DP

这代码快写死我了.....死人最多随便推推结论.死人最少,每个环可以单独考虑,每个环上挂着的每棵树也可以分别考虑.tarjan找出所有环,对环上每个点,求出选它和不选它时以它为根的树的最大独立集(就是最多活下来的人数),然后环上每个点选或不选对应的是一个“价值”,这个价值是那个点挂着的树里最多存活人数.先全都不选环上的点,算出选和不选时最大独立集的差值,问题变成有一个环,环上有一堆数(那些差值),选出一些不相邻的数使得和最大,然后我按着bzoj2151种树写了个贪心....这个贪心的思路也很神,

「Codeforces」758D(贪心细节/dp)

题意:原题在这 Alexander is learning how to convert numbers from the decimal system to any other, however, he doesn't know English letters, so he writes any number only as a decimal number, it means that instead of the letter A he will write the number 10.

将军令(贪心&amp;&amp;树形DP)

只看45分的话,是树形DP....(当然也有能拿到70分+的大佬) 40分: 只考虑k==1的情况,树形DP 所以每个节点可能被父亲,自己,儿子控制 设f[MAXN][3],0表示儿子,1表示自己,2表示父亲 f[i][1]+=min(f[to][0],f[to][1],f[to][2])(因为自己控制自己,儿子怎样都行) f[i][0]+=min(f[to][0],f[to][1]) 但是因为i的儿子必须有一个自己控制自己,所以还要判断所加值中是否有f[to][1],如果没有 f[i][0]+

CodeForces 1005D Polycarp and Div 3(思维、贪心、dp)

http://codeforces.com/problemset/problem/1005/D  题意: 给一个仅包含数字的字符串,将字符串分割成多个片段(无前导0),求这些片段里最多有多少是3的倍数 思路一(贪心): from:https://blog.csdn.net/islittlehappy/article/details/81006849 一个数是3的倍数,则各位的和能被3整除. 对于单独的一个数字,如果是3的倍数,则ans++ 否则,考虑连续的两个数字,如果是,则ans++ 如果第三