so就 (二分答案 dp 贪心)
2017-09-11 15:20
302 查看
so就
9.11思路:
明显的dp感觉,但是nk的复杂度又很恼火。当然有一种二分答案然后用dp来check的方法,就贴上代码不细说了。这里还有一种贪心的做法,用一个set来维护最大权值,之后每次从堆里取出堆顶元素,每次贪心的维护k=i时的ans(就只有k次循环),将堆顶元素和相邻的两个元素合并并修改权值,用链表维护相邻的关系,具体的实现还是看代码吧。
#include <iostream> #include <cstdio> #include <set> #define LL long long using namespace std; const int N = 100010; int n, k; LL ans, a ; int pre , nex ; struct node { LL w; int id; friend bool operator <(const node & a, const node & b){ return a.w==b.w ? a.id<b.id : a.w>b.w;} }; set<node> q; void solve() { while( k-- ){ node top = *q.begin(); q.erase((node){ top.w, top.id}); ans += (LL)a[top.id]; a[top.id] = a[pre[top.id]] + a[nex[top.id]] - a[top.id]; if( pre[top.id] ) q.erase((node){ a[pre[top.id]], pre[top.id]}); if( nex[top.id] ) q.erase((node){ a[nex[top.id]], nex[top.id]}); q.insert((node){ a[top.id], top.id}); if( pre[pre[top.id]] ) nex[pre[pre[top.id]]] = top.id; if( nex[nex[top.id]] ) pre[nex[nex[top.id]]] = top.id; pre[top.id] = pre[pre[top.id]]; nex[top.id] = nex[nex[top.id]]; } } int main(){ freopen ("so.in", "r", stdin); freopen ("so.out", "w", stdout); scanf("%d%d", &n, &k); a[0] = (LL)-1e17; for(int i=1; i<=n; i++){ scanf("%I64d", &a[i]); pre[i] = i-1, nex[i] = i+1; q.insert((node){ a[i], i}); } pre[1] = 0; nex = 0; solve(); printf("%I64d", ans); return 0; }
dp
#include <cstdio> #include <algorithm> #include <iostream> #include <cstring> using namespace std ; typedef long long LL ; int n, k ; const int MAXN = 100010 ; int a[MAXN]; LL b[MAXN] ; LL dp[MAXN][2] ; int minp[MAXN][2] ; int check(LL x) { for (int i = 1; i <= n; i ++) b[i] = x + a[i] ; for (int i = 1; i <= n; i ++) { dp[i][0] = dp[i - 1][0], minp[i][0] = minp[i - 1][0] ; if (dp[i - 1][1] > dp[i][0]) dp[i][0] = dp[i - 1][1], minp[i][0] = minp[i - 1][1] ; else if (dp[i - 1][1] == dp[i][0] && minp[i - 1][1] > minp[i][0]) minp[i][0] = minp[i - 1][1] ; dp[i][1] = dp[i - 1][0] + b[i], minp[i][1] = minp[i - 1][0] + 1 ; } if (dp [1] > dp [0]) return minp [1] ; if (dp [1] == dp [0]) return min(minp [1], minp [0]) ; return minp [0] ; } LL Calc(LL x) { for (int i = 1; i <= n; i ++) b[i] = a[i] + x; for (int i = 1; i <= n; i ++) { dp[i][0] = dp[i - 1][0], minp[i][0] = minp[i - 1][0] ; if (dp[i - 1][1] > dp[i][0]) dp[i][0] = dp[i - 1][1], minp[i][0] = minp[i - 1][1] ; else if (dp[i - 1][1] == dp[i][0] && minp[i - 1][1] > minp[i][0]) minp[i][0] = minp[i - 1][1] ; dp[i][1] = dp[i - 1][0] + b[i], minp[i][1] = minp[i - 1][0] + 1 ; } return max(dp [0], dp [1]) - 1LL * x * k ; } int main() { freopen("so.in", "r", stdin) ; freopen("so.out", "w", stdout) ; scanf("%d%d", &n, &k) ; for (int i = 1; i <= n; i ++) scanf("%d", &a[i]) ; LL l = - 10000000000LL, r = 10000000000LL ; while (l < r) { LL mid = (1LL * l + r + 20000000000LL) / 2 + 1 - 10000000000LL ; if (check(mid) > k) r = mid - 1 ; else l = mid ; } cout << Calc(l) << endl ; }
相关文章推荐
- 【bzoj2097】[Usaco2010 Dec]Exercise 奶牛健美操 二分答案+树形dp+贪心
- BZOJ 2097 USACO 2010 Dec Gold Exercise 奶牛健美操 二分答案 树形DP 贪心
- [贪心 模拟 + 二分答案 DP] BZOJ 1181 [CROATIAN2009]IZBROI选举
- <队内胡策> 2017.10.10 (贪心+二分答案+DP)
- BZOJ 2067 POI 2004 SZN 树形DP 贪心 二分答案
- [BZOJ2097][Usaco2010 Dec]Exercise 奶牛健美操(二分+树形dp+贪心)
- BZOJ 1044: [HAOI2008]木棍分割 DP,前缀和优化,二分答案
- LIS(最长上升子序列)的 DP 与 (贪心+二分) 两种解法
- Codeforces Round #424 (Div. 2, rated, based on VK Cup Finals) Problem D (Codeforces 831D) - 贪心 - 二分答案 - 动态规划
- bzoj2097 [Usaco2010 Dec]Exercise 奶牛健美操(二分答案+贪心+树)
- HDU 3586 Information Disturbing(二分答案+树形DP)
- 【二分答案+贪心】解决“最小值最大”问题(UVa 12124 - Assemble)
- codeforces 527D D. Clique Problem(二分+线段树+贪心+dp)
- bzoj 1863: [Zjoi2006]trouble 皇帝的烦恼(二分答案+dp)
- NKOJ 2650 (SDOI 2011) 消防(树的直径+DP+单调队列/二分答案)
- bzoj 4753: [Jsoi2016]最佳团体 二分答案+树形dp
- 道路覆盖 (二分答案+状压DP)
- BZOJ 4985: 评分 二分答案 dp判定
- 1044: [HAOI2008]木棍分割 二分答案+DP+前缀和优化
- bzoj 2525: [Poi2011]Dynamite 二分答案+树形贪心