2016D2T2 蚯蚓
2016D2T2 蚯蚓
problem
有\(n\)只蚯蚓,长度分别为\(a_i(i\in [1,n])\),每个时间可以选择一个蚯蚓进行切割,把它分割成\(\lfloor px\rfloor\) 和\(x-\lfloor px\rfloor(p\in[0,1]∩\mathbb Q)\)(这里注意,若任意一条为0,那么长度为0的蚯蚓仍然存在),同时其他的蚯蚓长度会增加\(q(q>0)\),现在想知道:
- \(m\)秒内,每一秒被切断的蚯蚓被切断之前的长度(\(m\)个数)
- \(m\)秒后,所有蚯蚓的长度(\(n+m\)个数)
solution
解题关键:隐藏的单调性
先被切掉的蚯蚓纷呈的蚯蚓一定要比后切掉的蚯蚓分成的蚯蚓大。
证明:
假设这两条蚯蚓分别是\(a,b(a>b)\),分别长\(l_a,l_b\),那么它被切成\(a_1,a_2\),这之后的\(t\)秒,\(b\)又被切成\(b_1,b_2\)。此时\(a_1,a_2\)的长度\(l_{a_1},l_{a_2}\)分别是
而\(b_1,b_2\)的长度为\(l_{b_1},l_{b_2}\),之后变成\(p(l_b+t),(1-p)(l_b+t)\),容易看出\(l_{a_1}>l_{b_1},l_{a_2}>l_{b_2}\),那么就是说如果蚯蚓\(a_1,a_2,...\),满足\(a_1>a_2>...\),那么以此分成\(a_{1,1},a_{1,2},a_{2,1},a_{2,2},...\),那么\(a_{1,2}>a_{2,2}>\cdots,a_{1,1}>a_{2,1}>\cdots\)
做法
我们可以想一下,对于每一秒除了被切得那一个之外所有的蚯蚓都增长\(q\)米,我们来维护3个队列,队列1表示最开始的蚯蚓,队列2表示每一次被切的蚯蚓被分开的较长的那一部分,队列3表示每一次被切的蚯蚓被分开的较短的那一部分。
我们先把原序列排序,因为不管怎么切,先被切的蚯蚓分成的两部分一定比后切的蚯蚓凤城的两部分大(见前方证明),所以我们可以省去每一秒增加每只蚯蚓的长度每个操作,转换成在查询砍那只蚯蚓的时候,把增加的长度算上增加的长度最大的蚯蚓,之后把他出队,切开的两部分分别进入队2、队3.
对于增量的计算,我们可以按照蚯蚓在队列中的标号。因为队列1中的蚯蚓直到被切是一种一直增长的状态,所以直接加上\((t_{pre}-1)q\)即可,而对于队列2和队列3的蚯蚓,他的增长是从被切掉的那一刻的下一秒开始的,所以他的增长量则是\((t_{pre}-t_{being-cut}-1)p\)
统计答案的时候合并三个队列,排序输出。
code
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <cstdio>
#include <iostream>
#include <cstring>
#include <cmath>
#include <cstdlib>
#include <algorithm>
using namespace std;
const int MAXN = 1e7;
inline int read(){
int w = 1, data = 0; char ch = 0;
while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if(ch == '-') w = -1, ch = getchar();
while(ch >= '0' && ch <= '9') data = data * 10 + ch - '0', ch = getchar();
return w * data;
}
int n, Q, m, T, h[10], t[10], tmp;
double u, v, p;
int q[4][MAXN], ans[MAXN];
inline void find(int x){
int num = 0, sum = 0;
for(int i = 1; i <= 3; i++){
if(i == 1 && q[i][h[i]] + x * Q > sum && h[i] < t[i]) num = i, sum = q[i][h[i]] + x * Q;
else if(q[i][h[i]] + (x-h[i])*Q > sum && h[i] < t[i]) num = i, sum = q[i][h[i]] + (x-h[i])*Q;
}
ans[x+1] = sum; tmp = sum; q[num][h[num]++];
}
int lxz[MAXN];
void Print_Ans(){
int num = 0;
for(int i = T, tot = 1; i <= m && tot <= m/T; i += T, tot++)
printf("%d ",ans[i]);
printf("\n");
for(int i = 1; i <= 3; i++){
for(int j = h[i]; j < t[i]; j++){
if(i == 1 && h[i] < t[i]) lxz[++num] = q[i][j] + (m) * Q;
else if(h[i] < t[i]) lxz[++num] = q[i][j] + (m-j)*Q;
}
}
sort(lxz+1, lxz+num+1, greater<int>());
for(int i = T, tot = 1; i <= num && tot <= (n+m)/T; i += T, tot++)
printf("%d ",lxz[i]);
}
int main(){
scanf("%d%d%d%lf%lf%d", &n, &m, &Q, &u, &v, &T);
p = u / v;
for(int i = 1; i <= 3; i++) h[i] = t[i] = 1;
for(int i = 1; i <= n; i++) q[1][i] = read(), t[1]++;
sort(q[1]+h[1], q[1]+t[1], greater<int>());
for(int i = 1; i <= m; i++){
find(i-1);
double a = floor(tmp * p), b = tmp - a;
if(a < b) swap(a, b);
q[2][t[2]++] = a; q[3][t[3]++] = b;
}
Print_Ans();
return 0;
}