[DBSDFZOJ 多校联训] 就
2017-08-07 17:21
267 查看
就
背景描述
一排 N 个数, 第 i 个数是 Ai , 你要找出 K 个不相邻的数, 使得他们的和最大。请求出这个最大和。
输入格式
第一行两个整数 N 和 K。接下来一行 N 个整数, 第 i 个整数表示 Ai 。
输出格式
一行一个整数表示最大和, 请注意答案可能会超过 int 范围样例输入
3 24 5 3
样例输出
7数据范围
对于 20% 的数据, N, K ≤ 20 。对于 40% 的数据, N, K ≤ 1000 。
对于 60% 的数据, N, K ≤ 10000 。
对于 100% 的数据, N, K ≤ 100000 , 1 ≤ Ai ≤ 1000000000。
第一眼看以为是个思博 $DP$ , 然后发现数据范围 $1 \times 10^{5}$ ...一股子 $O(nlog(n))$ 的味道...
一脸懵逼.png
然后就开始各种瞎**优化然后转背包然后就变成了 $60\%$ 的 $O(n^2)$ 算法.
正解果然特么是个贪心.
首先把所有的点都怼进一棵平衡树, 以权值降序第一关键字, 下标升序为第二关键字排序. 然后建立一个链表保存左侧第一个存在结点与右侧第一个存在结点的下标.
然后每次取值最大的元素, 将它和它左右的结点的数据从平衡树中删除, 再把对应的数据改成它的左侧结点与右侧结点的和减去它本身(为了保留不再选取该结点而改选两侧结点的可能性与结果的正确性). 然后修改联保中保存的左侧第二个与右侧第二个元素的右侧/左侧结点下标.
一直贪心 $k$ 次即可得解.总时间复杂度约为 $O(nlog(n))$
参考代码:
GitHub
#include <set> #include <cstdio> #include <cstring> #include <cstdlib> #include <iostream> #include <algorithm> #define int long long const int MAXN=1000010; const long long INF=0x3FFFFFFFFFFFFFFF; struct Node{ long long value; int pos; Node(long long value=0,int pos=0){ this->value=value; this->pos=pos; } bool friend operator <(const Node &tmp,const Node &y){ return tmp.value!=y.value?tmp.value>y.value:tmp.pos<y.pos; } }; int n; int k; long long ans; int next[MAXN]; int front[MAXN]; std::set<Node> s; long long data[MAXN]; void Initialize(); void Delete(int); signed main(){ Initialize(); while(k--){ int tmp=s.begin()->pos; ans+=data[tmp]; data[tmp]=data[front[tmp]]+data[next[tmp]]-data[tmp]; s.erase(s.begin()); s.erase(Node(data[front[tmp]],front[tmp])); s.erase(Node(data[next[tmp]],next[tmp])); s.insert(Node(data[tmp],tmp)); Delete(tmp); } printf("%lld\n",ans); return 0; } void Delete(int tmp){ if(front[front[tmp]]){ next[front[front[tmp]]]=tmp; } if(next[next[tmp]]){ front[next[next[tmp]]]=tmp; } front[tmp]=front[front[tmp]]; next[tmp]=next[next[tmp]]; } void Initialize(){ scanf("%lld%lld",&n,&k); for(int i=1;i<=n;i++){ scanf("%lld",data+i); front[i]=i-1; next[i]=i+1; s.insert(Node(data[i],i)); } data[0]=-INF; next =0; }
Backup
以及日常图包
相关文章推荐
- [DBSDFZOJ 多校联训] Password
- 【DBSDFZOJ 4460】666(DP)
- 【DBSDFZOJ 4409】a(离散化+树状数组)
- 【DBSDFZOJ 4370】小宁的机器人(模拟)
- 【DBSDFZOJ 4844】区间(分治)
- 【DBSDFZOJ 4415】黄金拼图(乱搞)
- 【乱搞】【DBSDFZOJ 4415】黄金拼图
- 【DBSDFZOJ 4845】三元组(树状数组)
- 【DBSDFZOJ 4846】攻略(贪心)
- 【DBSDFZOJ 4847】环线(矩阵快速幂)
- 【转】【DBSDFZOJ 1163】分治 第K小元素(分治)
- 【模板】进制转换【DBSDFZOJ】
- 【DBSDFZOJ 4445】棋盘(组合数学-错排公式+高精度)
- 【DBSDFZOJ 4430】陶陶摘苹果(DP)
- 【DBSDFZOJ 4448】a(乱搞)
- [DFS]FJSDFZOJ 1261 整数拆分
- [字符串]FJSDFZOJ 1075 统计单词数
- FJSDFZOJ 1109 统计数字
- [DP]FJSDFZOJ 1386 最大连续子段和问题
- [DFS]FJSDFZOJ 1079/NOIP2002 选数