• 【NOIP2016提高组day2】蚯蚓


    题目

    本题中,我们将用符号 LcJ 表示对 c 向下取整,例如: L3.0J = L3.1J = L3.9J = 3 。 蛐蛐国最近蚯蚓成灾了!隔壁跳蚤国的跳蚤也拿蚯蚓们没办法,蛐蛐国王只好去 请神刀手来帮他们消灭蚯蚓。
    蛐蛐国里现在共有 n 只蚯蚓( n 为正整数)。 每只蚯蚓拥有长度,我们设第 i 只匠 蚓的长度为 ai ( i = 1, 2, . . . , n ),并保证所有的长度都是非负整数(即:可能存在长度为 0 的蚯蚓)。
    每一秒,神刀手会在所有的蚯蚓中,准确地找到最长的那一只(如有多个则任选 一个)将其切成两半。 神刀手切开蚯蚓的位置由常数 p (是满足 0 < p < 1 的有理数) 决定,设这只蚯蚓长度为 x ,神刀手会将其切成两只长度分别为 LpxJ 和 x − LpxJ 的匠 蚓。特殊地,如果这两个数的其中一个等于 0 ,则这个长度为 0 的蚯蚓也会被保留。此 外,除了刚刚产生的两只新蚯蚓,其余蚯蚓的长度都会增加q(是一个非负整常数)。
    蛐蛐国王知道这样不是长久之计,因为蚯蚓不仅会越来越多,还会越来越长。蛐蛐国王决定求助于一位有着洪荒之力的神秘人物,但是救兵还需要 m 秒才能到来. . . . . . ( m 为非负整数)
    蛐蛐国王希望知道这 m 秒内的战况。 具体来说,他希望知道: • m 秒内,每一秒被切断的蚯蚓被切断前的长度(有 m 个数): • m 秒后,所有蚯蚓的长度(有 n + m 个数)。 蛐蛐国王当然知道怎么做啦! 但是他想考考你. . . . . .

    分析

    这题很坑爹,
    假设有两个数x、y,先后被切(x>y),那么
    分别分成xp,x(1-p),yp,y(1-p)。
    那么会先切那条呢?
    发现,因为增长的速度一样,所以就只比较切完y之后。
    (x:xp+q)
    (y:(y+q)p=yp+qp)
    显然$$xp+q>yp+qp$$
    于是将xp放在yp前面
    x(1-p),y(1-p)同理。
    那么我们开三个不上升队列,
    第一个记录原来的蚯蚓,
    第二个记录乘以p的蚯蚓
    第三个记录乘以(1-p)的蚯蚓,
    在记录每条就要入队列的时间,就可以求出增加的长度
    每次比较三个队列的队首,取最大的值x的切。
    将xp加入第二个队列的队尾
    将x(1-p)加入第三个队列的队尾
    (第二个第三个队列保证单调,上面证明了)

    #include <cmath>
    #include <iostream>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <algorithm>
    #include <queue>
    const int maxlongint=2147483647;
    const int mo=1000000007;
    const int N=7100005;
    using namespace std;
    struct ddx
    {
    	int v,t;
    }d[3][N];
    int s[3],t[3],n,m,tt,q,v,u;
    bool cmp(ddx x,ddx y)
    {
    	return x.v>y.v;
    }
    int get(int i,int x)
    {
    	if(s[i]>t[i]) return -maxlongint;
    	return d[i][s[i]].v+q*(x-d[i][s[i]].t-1);
    }
    int compete(int x)
    {
    	int pos=0;
    	for(int i=0;i<=2;i++)
    	{
    		if(s[i]<=t[i])
    			if(get(i,x)>get(pos,x)) pos=i;
    	}
    	return pos;
    }
    int main()
    {
    	freopen("earthworm.in","r",stdin);
    	freopen("earthworm.out","w",stdout);
    	scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&tt);
    	for(int i=1;i<=n;i++) scanf("%d",&d[0][i].v);
    	sort(d[0]+1,d[0]+1+n,cmp);
    	s[0]=s[1]=s[2]=1;
    	t[0]=n;
    	for(int i=1;i<=m;i++)
    	{
    		int pos=compete(i),val=get(pos,i);
    		if(i%tt==0) printf("%d ",val);
    		s[pos]++;
    		d[1][++t[1]].v=int(u*1.0/v*val);
    		d[2][++t[2]].v=val-int(u*1.0/v*val);
    		d[1][t[1]].t=i;
    		d[2][t[2]].t=i;
    	}
    	cout<<endl;
    	for(int i=1;i<=n+m;i++)
    	{
    		int pos=compete(m+1),val=get(pos,m+1);
    		if(i%tt==0) printf("%d ",val);
    		s[pos]++;
    	}
    }
    
  • 相关阅读:
    redis面试题
    git简单介绍常用操作
    K8S 四种client简单介绍
    kubebuilder之二:kubebuilder的用法
    《灿烂千阳》读后感
    为什么不能放弃自己的特产生意
    抖音小程序变现
    股票分析市净率
    咸鱼无货源
    cpi与ppi
  • 原文地址:https://www.cnblogs.com/chen1352/p/9066584.html
Copyright © 2020-2023  润新知