首页 > 代码库 > 2017.8.7 联考 就 贪心(有反悔策略)

2017.8.7 联考 就 贪心(有反悔策略)

【背景描述】

一排 N 个数, 第 i 个数是 Ai , 你要找出 K 个不相邻的数, 使得他们的和最大。

请求出这个最大和。

【输入格式】

第一行两个整数 N 和 K。

接下来一行 N 个整数, 第 i 个整数表示 Ai 。

【输出格式】

一行一个整数表示最大和, 请注意答案可能会超过 int 范围

【样例输入】

3 2

4 5 3

【样例输出】

7

【数据范围】

对于 20% 的数据, N, K ≤ 20 。

对于 40% 的数据, N, K ≤ 1000 。

对于 60% 的数据, N, K ≤ 10000 。

对于 100% 的数据, N, K ≤ 100000 , 1 ≤ Ai ≤ 1000000000。

solution

(别问我这个题目是什么意思...)

(再吐槽一下,long long是8字节 long long是8字节 long long是8字节,我考试按int 算的,结果MLE了.....)

(算上第二题已经 扔了150了)

60分  dp:

f[i][k] 第i个位置一定选  当前加上第i个已经选了k个

f[i][k]=max(f[i][k],f[j][k-1]+a[i])  j<i-1 

枚举i 枚举k 枚举j O(n^3)

但是枚举j可以用一个数组记录下来

优化为  O(n^2)

100分  贪心+反悔(有堆维护):

我们先把每一个位置压成一个  (pos,val) 的结构体,推入堆中

然后从中取最大的 i 取k次

每取一次,就把他两边的合并起来 (已经合并过一次的可以再合并) (可以用链表) 

把堆中原来的自己、左右两边的都删掉,然后把自己压成 (pos[i],val[i-1]+val[i+1]-val[i])推入堆

证明  val[i-1]+val[i+1]-val[i]:

        i-1      i        i+1      x

只有当    val[i-1]+val[i+1]>val[i]+val[x]  时,才是更优的

                val[i-1]+val[i+1]-val[i]>val[x]

  把左式存入结构体即可

技术分享
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cstring>
 4 #include<set>
 5 #define ll long long
 6 using namespace std;
 7 const int N=100066;
 8 const ll INF=((ll)1<<62);
 9 int intmax(int a,int b){return a>b?a:b;}
10 int intmin(int a,int b){return a<b?a:b;}
11 ll llmax(ll a,ll b){return a>b?a:b;}
12 
13 struct son
14 {
15     int pos;
16     ll val;
17     son(int posss,ll valll)
18     {
19         pos=posss;val=valll;
20     }
21     friend bool operator < (son a,son b)
22     {
23         return a.val>b.val;
24     }
25 };
26 int n,kk,pre[N],nxt[N];
27 ll a[N];
28 
29 set<son> q;
30 ll ans;
31 
32 int main(){
33     
34     scanf("%d%d",&n,&kk);
35     for(int i=1;i<=n;++i)
36     {
37         scanf("%lld",&a[i]);
38         pre[i]=i-1;nxt[i]=i+1;
39         q.insert(son(i,a[i]));
40     }
41     a[0]=-INF;
42     a[n+1]=-INF;
43     nxt[n+1]=n+1;
44     for(int i=1;i<=kk;++i)
45     {
46         int now=q.begin()->pos;
47         ans+=a[now];
48         q.erase( son(now,a[now]) );
49         a[now]=a[pre[now]]+a[nxt[now]]-a[now];
50         q.insert(son(now,a[now]));
51         if(pre[now]!=0) q.erase( son(pre[now],a[pre[now]]) );
52         if(nxt[now]!=n+1) q.erase( son(nxt[now],a[nxt[now]]) );
53         
54         nxt[pre[pre[now]]]=now;
55         pre[nxt[nxt[now]]]=now;
56         pre[now]=pre[pre[now]];
57         nxt[now]=nxt[nxt[now]];
58     }
59     
60     cout<<ans;
61     //while(1);
62     return 0;
63 }
code

 

2017.8.7 联考 就 贪心(有反悔策略)