NOIP2016Day2T2蚯蚓解题报告
2017-09-02 12:22
204 查看
原题目见洛谷(https://www.luogu.org/problem/show?pid=2827)
其实这道题的数据特点写得非常详细个人认为这道题即使是纯暴力也可以得到25分。下面我来分分数段来讲解这道题:
【25分】
首先我们来看数据范围在第1.2.3个点我们发现数据m=0那么直接按题目方式输出就好了,第4.6个点n=1也直接暴力模拟就好了,具体代码不写了……
【65-85分】
我们最先想到的是用堆来维护所有蚯蚓的长度,如何来操作呢:我们每次从堆中取出最长的蚯蚓,将他切割后放入堆中。
那么就产生了一个问题:我们每次将蚯蚓取出后如何使得其他蚯蚓的长度增加q?
我们可以这么来做,用一个Add来记录当前每条蚯蚓应当增加的长度当我们的时间已经到达m时说明所有切割结束,那么理论上每一条蚯蚓都增加了Add=q*m的长度。但是当我们取出一条需要切割的蚯蚓时,这条蚯蚓的长度是不允许增加的,我们如何来操作呢?我们在切割后蚯蚓的长度上减去q在压入堆中就可以了,我们可以采用手打堆和快速输入输出来让程序跑得更快。用STL模板中的priority_queue时会T掉一些点,我在这里采用手打堆和输入输出优化分数为85分,此时算法时间复杂度约为O((n+m)log(n+m))代码如下:
【100分】
现在我们改进一下,我们这样
想,如果我们将原来的蚯蚓设为l1,分割后的两条蚯蚓分别设为l2,l3,那么一定有l2<=l1,l3<=l1显然成立那么我们可以定义三个普通队列分别表示未切割过的的蚯蚓q1,切割过的左半段q2,切割过的有半段q3,输入完数据时将q1从大到小排序,每次需要切割时取出三个队列中队首的最大值切割就好之后将切割后的左右段分别压入q2,q3的队尾其他处理方式和用堆处理方式相同,于是算法时间复杂度为O(n+m),显然要快很多,总共用时1528ms
其实这道题的数据特点写得非常详细个人认为这道题即使是纯暴力也可以得到25分。下面我来分分数段来讲解这道题:
【25分】
首先我们来看数据范围在第1.2.3个点我们发现数据m=0那么直接按题目方式输出就好了,第4.6个点n=1也直接暴力模拟就好了,具体代码不写了……
【65-85分】
我们最先想到的是用堆来维护所有蚯蚓的长度,如何来操作呢:我们每次从堆中取出最长的蚯蚓,将他切割后放入堆中。
那么就产生了一个问题:我们每次将蚯蚓取出后如何使得其他蚯蚓的长度增加q?
我们可以这么来做,用一个Add来记录当前每条蚯蚓应当增加的长度当我们的时间已经到达m时说明所有切割结束,那么理论上每一条蚯蚓都增加了Add=q*m的长度。但是当我们取出一条需要切割的蚯蚓时,这条蚯蚓的长度是不允许增加的,我们如何来操作呢?我们在切割后蚯蚓的长度上减去q在压入堆中就可以了,我们可以采用手打堆和快速输入输出来让程序跑得更快。用STL模板中的priority_queue时会T掉一些点,我在这里采用手打堆和输入输出优化分数为85分,此时算法时间复杂度约为O((n+m)log(n+m))代码如下:
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; const int N = 1e5 + 5, M = 7e6 + 5; int n, m, q, u, v, t, Add; double p; struct BigRt { int g[N + M], l; inline void Pop() { g[1] = g[l--]; int now = 1, nxt = 2, res = g[1]; while (nxt <= l) { if (nxt < l && g[nxt | 1] > g[nxt]) nxt |= 1; if (res < g[nxt]) g[now] = g[nxt], nxt = (now = nxt) << 1; else break; } g[now] = res; } inline void Push(const int &res) { g[++l] = res; int now = l, nxt = l >> 1; while (nxt) { if (res > g[nxt]) g[now] = g[nxt], nxt = (now = nxt) >> 1; else break; } g[now] = res; } }Q; inline int get() { char ch; int res = 0; bool f = true; while (((ch = getchar()) < '0' || ch > '9') && ch != '-'); if (ch == '-') f = false; else res = ch - '0'; while ((ch = getchar()) >= '0' && ch <= '9') res = (res << 3) + (res << 1) + ch - '0'; return f? res : -res; } inline void put(int x) { if (x < 0) x = -x, putchar('-'); if (x > 9) put(x / 10); putchar(x % 10 + 48); } inline bool cmp(const int &x, const int &y) {return x > y;} int main() { n = get(); m = get(); q = get(); u = get(); v = get(); t = get(); p = (double)u / v; Q.l = 0; for (int i = 1; i <= n; ++i) Q.Push(get()); for (int i = 1; i <= m; ++i) { int x = Q.g[1] + Add; Q.Pop(); if (i % t == 0) put(x), putchar(' '); int l = (int)(p * x), r = x - l; Q.Push(l - Add - q); Q.Push(r - Add - q); Add += q; (i % t == 0) put(Q.g[1] + Add), putchar(' '); Q.Pop(); } }
【100分】
现在我们改进一下,我们这样
想,如果我们将原来的蚯蚓设为l1,分割后的两条蚯蚓分别设为l2,l3,那么一定有l2<=l1,l3<=l1显然成立那么我们可以定义三个普通队列分别表示未切割过的的蚯蚓q1,切割过的左半段q2,切割过的有半段q3,输入完数据时将q1从大到小排序,每次需要切割时取出三个队列中队首的最大值切割就好之后将切割后的左右段分别压入q2,q3的队尾其他处理方式和用堆处理方式相同,于是算法时间复杂度为O(n+m),显然要快很多,总共用时1528ms
#include <iostream> #include <cstdio> #include <algorithm> #include <cmath> using namespace std; typedef long long ll; const i 4000 nt Maxn = 2147483647; const int N = 1e5 + 5, M = 7e6 + 5; int n, m, q, u, v, t, Add; int Q[3][M], qt[3], qw[3]; inline int get() { char ch; int res; while ((ch = getchar()) < '0' || ch > '9'); res = ch - '0'; while ((ch = getchar()) >= '0' && ch <= '9') res = (res << 3) + (res << 1) + ch - '0'; return res; } inline void put(int x) { if (x > 9) put(x / 10); putchar(x % 10 + 48); } inline bool cmp(const int &x, const int &y) {return x > y;} inline int GetMax() { int res = -Maxn, k; for (int i = 0; i < 3; ++i) if (qt[i] < qw[i] && res < Q[i][qt[i] + 1]) res = Q[i][qt[i] + 1], k = i; qt[k]++; return res; } int main() { n = get(); m = get(); q = get(); u = get(); v = get(); t = get(); for (int i = 1; i <= n; ++i) Q[0][++qw[0]] = get(); sort(Q[0] + 1, Q[0] + qw[0] + 1, cmp); for (int i = 1; i <= m; ++i) { int x = GetMax() + Add; if (i % t == 0) put(x), putchar(i + t > m ? '\n' : ' '); int l = (ll)x * u / v, r = x - l; Q[1][++qw[1]] = l - Add - q; Q[2][++qw[2]] = r - Add - q; Add += q; } if (t > m) putchar('\n'); int tmp = n + m; for (int i = 1; i <= tmp; ++i) { int x = GetMax() + Add; if (i % t == 0) {put(x); if (i + t <= tmp) putchar(' ');} } return 0; }
相关文章推荐
- Noip2016 提高d2 蚯蚓 解题报告
- LuoguP2827/UOJ264[NOIP2016D2T2]蚯蚓 解题报告【单调队列】
- NOIP2017 提高Day2-2 宝藏 解题报告
- NOIP2016提高组复赛解题报告
- NOIP2011 mayan游戏 解题报告(搜索)
- NOIP2011解题报告-Day2
- NOIP2014 寻找道路 解题报告(dfs+bfs)
- NOIP2000 解题报告
- [NOIP2017]提高组解题报告
- NOIP2008解题报告(C/C++)(笨小猴)(火柴棒等式)(传纸条)(双栈排序)
- [NOIP2005] 采药-解题报告
- 2016.7.12 NOIP2013提高组 day2解题报告(未完成版)
- 20161022 NOIP模拟赛 解题报告
- NOIP2015 普及组(Junior) 解题报告
- 20161023 NOIP 模拟赛 T1 解题报告
- 全国信息学奥林匹克联赛(NOIP2010)复赛 1.数字统计 解题报告
- 20161022 NOIP模拟赛 T1 解题报告
- 全国信息学奥林匹克联赛(NOIP2010)复赛 3.导弹拦截 解题报告
- LuoguP2822[NOIP2016] 组合数问题 解题报告【组合数取模+矩阵前缀和】
- NOIP 2003解题报告