题目分享T
Posted lin4xu
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题目分享T相关的知识,希望对你有一定的参考价值。
题意:蛐蛐国里现在共有n只蚯蚓(n为正整数)。每只蚯蚓拥有长度,我们设第i只蚯蚓的长度为a_i(i=1,2,...,n),并保证所有的长度都是非负整数(即:可
能存在长度为0的蚯蚓)。每一秒,神刀手会在所有的蚯蚓中,准确地找到最长的那一只(如有多个则任选一个)
将其切成两半。神刀手切开蚯蚓的位置由常数p(是满足0<p<1的有理数)决定,设这只蚯蚓长度为x,神刀手会将其
切成两只长度分别为[px]和x-[px]的蚯蚓。特殊地,如果这两个数的其中一个等于0,则这个长度为0的蚯蚓也会被
保留。此外,除了刚刚产生的两只新蚯蚓,其余蚯蚓的长度都会增加q(是一个非负整常数)。蛐蛐国王知道这样不
是长久之计,因为蚯蚓不仅会越来越多,还会越来越长。蛐蛐国王决定求助于一位有着洪荒之力的神秘人物,但是
救兵还需要m秒才能到来......(m为非负整数)蛐蛐国王希望知道这m秒内的战况。具体来说,他希望知道:?m秒内
,每一秒被切断的蚯蚓被切断前的长度(有m个数)?m秒后,所有蚯蚓的长度(有n+m个数)。
第一行包含六个整数n,m,q,u,v,t,其中:n,m,q的意义见问题描述;
u,v,t均为正整数;你需要自己计算p=u/v(保证0<u<v)t是输出参数,其含义将会在输出格式中解释。
第二行包含n个非负整数,为ai,a2,...,an,即初始时n只蚯蚓的长度。
同一行中相邻的两个数之间,恰好用一个空格隔开。
保证1<=n<=10^5,0<m<7*10^6,0<u<v<10^9,0<=q<=200,1<t<71,0<ai<10^8。
分析:一看到这个题很容易想到优先队列来维护,但再一看数据范围mlgm的复杂度很难接受,那么就可以考虑利用已有的单调性减少用优先队列维护的次数,相当于根据题目的数据优化优先队列,甚至不用优先队列
首先考虑两个蚯蚓x,y,令x>y
则x要比y先被切,假设x是第tx秒被切,y是第ty秒被切,显然tx<ty
那么x在切之前长度就应该是x0+(tx-1)*q,而切之后会变成两段,一段为[xp],另一段位x-[xp]
当然y也同理
在切之前长度是y0+(ty-1)*q,切后两段是[yp]和y-[yp]
再设一个时间t表示两蚯蚓都被切后的某个时间
那么x那两段的长度就应该是[xp]+(t-tx)*q,(x-[xp])+(t-tx)*q
y那两段的长度就应该是[yp]+(t-ty)*q,(y-[yp])+(t-ty)*q
这里很容易发现[xp]>[yp],(t-tx)*q>(t-ty)*q,(x-[xp])>(y-yp),
也就是说x被切成的两段永远大于y被切成的两段
所以对于被这两段中的每一段都满足先来的大于后来的,所以可以用队列维护,新入队的就是最小的,先入队的就是最大的
所以要开两个队列,维护这两种被切割的段,因为最大的永远在队首,所以只需要将原蚯蚓中最大的与这两个队列的队首找个最大的就可以确定当前选出要被切割的蚯蚓,切完后再push到这两个队列里即可
当然,在原蚯蚓中找最大也可以sort一下,写个指针指向最大值就行了
这里虽然看似优化到了O(n)但是常数还是卡的稍微有点死,这里有一些优化的方法 以及加速的多少(1-5:少-多)
1.快读 |3|(这里输入个数较少(1e5))
int read() { char ch=getchar();int ans=0; while(ch>‘9‘||ch<‘0‘) ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘) { ans=(ans<<1)+(ans<<3)+ch-‘0‘; ch=getchar(); } return ans; }
2.快输 |4|(这里输出个数较多(1e7))
void write(int x) { if(x>9) write(x/10); putchar(x%10+‘0‘); }
3.i++改为++i |1|
for(int i=1;i<=m;++i)
4.stl改为手写队列 |3|
for(int i=1;i<=a_cnt;++i) d[++d_cnt]=a[i]+sum; for(int i=b_str;i<=b_end;++i) d[++d_cnt]=b[i].val+sum-b[i].tim; for(int i=c_str;i<=c_end;++i) d[++d_cnt]=c[i].val+sum-c[i].tim;
5.将相同的运算开变量先存结果,比如+q*m要算多次,就开qm=q*m然后后面都用qm代替q*m |5|(这里真的加快很多,因为类似的乘法运算估计要被优化5e7次以上)
int sum=q*(i-1); int nowa=((!a_cnt)?-1:(a[a_cnt]+sum)); int nowb=((b_str>b_end)?-1:(b[b_str].val+sum-b[b_str].tim)); int nowc=((c_str>c_end)?-1:(c[c_str].val+sum-c[c_str].tim));
6.在写代码的时候尽量将数据利用到最大化,比如某些地方交换运算顺序能将同样的运算简化 |2|
sum+=q; b[++b_end].val=now*p,b[b_end].tim=sum; c[++c_end].val=now-b[b_end].val;c[c_end].tim=sum;
……
大概优化就分为 思路上的优化,代码上的优化以及细节上的优化,显然在我们思路优化已经到顶的时候某些代码上的优化能使运行速度快不少(快读,快输,手写队列,变量存结果)
代码:
#include<cstdio> #include<algorithm> #include<queue> #include<cstring> using namespace std; #define ll long long const int maxn=1e7+1; struct Node { int tim,val; }b[maxn],c[maxn]; int a[maxn],d[maxn]; int read() { char ch=getchar();int ans=0; while(ch>‘9‘||ch<‘0‘) ch=getchar(); while(ch<=‘9‘&&ch>=‘0‘) { ans=(ans<<1)+(ans<<3)+ch-‘0‘; ch=getchar(); } return ans; } void write(int x) { if(x>9) write(x/10); putchar(x%10+‘0‘); } int main() { int u,v,n,m,t,q,a_cnt,b_str,b_end,c_str,c_end,d_cnt; double p; n=read(),m=read(),q=read(),u=read(),v=read(),t=read(); p=(double)u/v; for(int i=1;i<=n;++i) a[i]=read(); sort(a+1,a+n+1); a_cnt=n,b_end=c_end=d_cnt=0,b_str=c_str=1; for(int i=1;i<=m;++i) { int now,sum=q*(i-1); int nowa=((!a_cnt)?-1:(a[a_cnt]+sum)); int nowb=((b_str>b_end)?-1:(b[b_str].val+sum-b[b_str].tim)); int nowc=((c_str>c_end)?-1:(c[c_str].val+sum-c[c_str].tim)); if(nowa>=nowb&&nowa>=nowc) now=nowa,--a_cnt; else if(nowb>=nowc&&nowb>=nowa) now=nowb,++b_str; else now=nowc,++c_str; sum+=q; b[++b_end].val=now*p,b[b_end].tim=sum; c[++c_end].val=now-b[b_end].val;c[c_end].tim=sum; if(i%t==0) write(now),putchar(‘ ‘); } putchar(‘ ‘); int sum=q*m; for(int i=1;i<=a_cnt;++i) d[++d_cnt]=a[i]+sum; for(int i=b_str;i<=b_end;++i) d[++d_cnt]=b[i].val+sum-b[i].tim; for(int i=c_str;i<=c_end;++i) d[++d_cnt]=c[i].val+sum-c[i].tim; sort(d+1,d+d_cnt+1); for(int i=d_cnt+1-t;i>=1;i-=t) write(d[i]),putchar(‘ ‘); putchar(‘ ‘); return 0; }
以上是关于题目分享T的主要内容,如果未能解决你的问题,请参考以下文章