1的写法有想法,但是因为时间复杂度太高所以走不通
首先,我前面的思路是使用优先队列来进行,但是优先队列的插入复杂度是\(O(log (n+m))\),总共m次操作,总复杂度为\(O(mlog(n+m))\),在\(1 \leq n \leq 10^5\),\(0 \leq m \leq 7 \times 10^6\)的情况下肯定会超时,所以我们需要再想想。
再看题目,每一次取出,将最大的劈成固定比例的两份,其他的加上q,而且\(0 \leq q \leq 200\),所以我们可以发现这样的一个现象:
- 5, 4取出5,假设按照p=0.25来将5变成1和4,原本的4加上1变成5,整理一下是5,4,1
- 5,4,1取出5,变成1和4,原本的4和1加上1变成5和2,整理就是5,4,2,1
发现了吗,原本的变完以后的第一个5来自原本的5的较大份,4来自原本4的较大份,2来自原本5的较小份,1来自原本4的较小份
说明了将蚯蚓处理后的两份分开存储,长度的单调递增的(可以多试几组数据检验)
简单来说:
设 \(a\) 为降序数组且长度为 \(n\)。
\(f_1(x)\) 可以得到长度 \(x\) 分裂的第一段。
\(f_2(x)\) 可以得到长度 \(x\) 分裂出来的第二段,且满足:
\(f_1(x)\) 展开为:
\(f_2(x)\) 展开为:
(全程 \(\frac{1}{2} < p < 1\))
简单来说:
已知 \(a_0 \ge a_1\),经过分裂后和加 \(q\) 后:
\(a_0\) 变成了 \(f_1(a_0) + q\) 和 \(f_2(a_0) + q\)
\(a_1\) 变成了 \(f_1(a_1 + q)\) 和 \(f_2(a_1 + q)\)
将 \(a_1 + q\) 带入原函数 \(f_1\),得:
展开为:
还原为:
将 \(a_1 + q\) 带入原函数 \(f_2\),展开为:
整理为:
还原为:
因为 \(a_0 \ge a_1\),所以:
\(f_2\) 同理。
同样由定义可知:
所以:
基于这个思想,我们将原本的所有蚯蚓长度降序排序,压入一个队列中,另外准备两个队列,用来存储劈开后的两个蚯蚓
每一次从3个队列头部中选出最大的那个,然后弹出去,计算偏移量,题目中说是其他的全部加一个q,其实等同于分裂出来的这两个减掉一个q,相对来说效果一样,只不过每一次需要真实值的时候需要计算真实值,设当前是第\(k\)秒,那么一个没有被切过的蚯蚓长度应该是\(x+kq\)(x为原本的长度),而且分裂前需要计算原蚯蚓的真实长度(注意!这个长度应该是\(x+(k-1)q\),因为现在第\(k\)秒的增加还没有发生)
还有,使用double存p然后和x相乘会产生轻微的误差,而且整个代码只有一处用到了p,所以这里将p换成u/v
但是!\(0 < u \leq 10^9\)且\(0 \leq a_i \leq 10^8\),算出来直接爆int,所以我们要将其中一个变为long long来算才行
十年OI一场空,不开long long见祖宗
最后的收尾就是将原本计算真实长度的\(x+kq\)换成\(x+mq\)罢了,但是一定要还原了真实长度以后再降序排序。
AC代码
#include <algorithm>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
typedef long long ll;
vector<int> vec;
int n,m,q,u,v,t;
queue<int> qu[3]; // 0是原本的,1是px的,2是x-px的
int main() {ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);cin>>n>>m>>q>>u>>v>>t;for(int i=1; i<=n; i++) {int a; cin>>a;vec.push_back(a);}sort(vec.begin(), vec.end(), [](int a, int b) {return a > b;});for(auto i : vec) qu[0].push(i);int de = 0;for(int k=1; k<=m; k++) {int idx = 0;for(int i=0; i<3; i++) {if(!qu[i].empty()) {if(qu[idx].empty() || qu[i].front() > qu[idx].front()) idx = i;}}int x = qu[idx].front() + de;if(k % t == 0) cout<<x<<" ";int px = (ll)x * u / v; de += q;qu[1].push(px-de); qu[2].push(x-px-de);qu[idx].pop();}cout<<endl;vector<int> v;for(int i=0; i<3; i++) {while(!qu[i].empty()) {v.push_back(qu[i].front() + de);qu[i].pop();}}sort(v.begin(), v.end(), [](int a, int b){return a > b;});for(int i=0; i<v.size(); i++) {if((i+1) % t == 0) cout<<v[i]<<" ";}return 0;
}
