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)\),现在想知道:

  1. \(m\)秒内,每一秒被切断的蚯蚓被切断之前的长度(\(m\)个数)
  2. \(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}\)分别是

\[l_{a_1}+t=pl_a+t,l_{a_2}+t=(1-p)l_a+t \]

\(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;
}
posted @ 2020-10-19 16:06  刘子闻  阅读(70)  评论(0编辑  收藏  举报