• 【洛谷2827】蚯蚓(单调队列+三路归并)


    点此看题面

    大致题意:(n)只长度为自然数(可能为(0))的蚯蚓,每一秒会将最长的蚯蚓切成两半:长度分别为 (lfloor px floor)(x-lfloor px floor)(长度为(0)的蚯蚓也会被保留),此外,除了刚产生的两只蚯蚓,其余蚯蚓的长度都会增加(q),现在要你求出(m)秒内每一秒被切断的蚯蚓在被切断前的长度和m秒后所有蚯蚓的长度(从大到小)。

    题解

    这道题目题意看起来比较复杂,其实我们可以这样考虑:
    先将原始蚯蚓长度从大到小排序,每一次将砍断后蚯蚓较长的一段较短的一段分别存入两个数组中,由于被砍断的蚯蚓的原始长度是递减的,因此我们可以保证原始数组以及新建的两个数组满足不严格单调递减的性质,因此每次砍断的蚯蚓必然位于三个数组的队首,从而可以再接近于(O(1))的时间内确定接下来要砍断的蚯蚓。
    最后,再将这三个有序的数组进行三路归并等价于两次二路归并),然后即可求出答案。

    代码

    #include<bits/stdc++.h>
    #define max(x,y) ((x)>(y)?(x):(y))
    #define min(x,y) ((x)<(y)?(x):(y))
    #define LL long long
    #define N 100000
    #define M 7000000
    using namespace std;
    LL n,m,q,u,v,t,a[N+5],b[M+5],c[M+5],s[N+M+5],s_[N+M+5]; 
    inline char tc()
    {
    	static char ff[100000],*A=ff,*B=ff;
    	return A==B&&(B=(A=ff)+fread(ff,1,100000,stdin),A==B)?EOF:*A++;
    }
    inline void read(LL &x)
    {
    	x=0;char ch;
    	while(!isdigit(ch=tc()));
    	while(x=(x<<3)+(x<<1)+ch-'0',isdigit(ch=tc()));
    }
    inline void write(LL x)
    {
    	if(x>9) write(x/10);
    	putchar(x%10+'0');
    }
    bool cmp(LL x,LL y)
    {
    	return x>y;
    }
    void merge(LL *X,LL *Y,int H1,int T1,int H2,int T2)//二路归并,将X[]与Y[]两个数组进行归并,并保证其有序
    {
    	int i=H1-1,j=H2-1,k=0;
    	while(i<T1&&j<T2)
    	{
    		if(X[i+1]>Y[j+1]) s[++k]=X[++i];
    		else s[++k]=Y[++j]; 
    	}
    	while(i<T1) s[++k]=X[++i];
    	while(j<T2) s[++k]=Y[++j];
    }
    int main()
    {
    	register int i;
    	for(read(n),read(m),read(q),read(u),read(v),read(t),i=1;i<=n;++i) read(a[i]);
    	sort(a+1,a+n+1,cmp);//将原始数组a[]数组按从大到小的顺序排序
    	int H1=1,H2=1,H3=1,T2=0,T3=0;//分别记录a[]数组的队首、b[]数组的队首和队尾以及c[]数组的队首与队尾
    	LL tot=-q;//初始化增长的总长度
    	for(i=1;i<=m;++i)
    	{
    		tot+=q;//更新增长的总长度
    		LL Max=max(H1<=n?a[H1]:-tot-q,max(H2<=T2?b[H2]:-tot-q,H3<=T3?c[H3]:-tot-q))+tot;//求出最长的蚯蚓的长度
    		if(!(i%t)) write(Max),putchar(' ');
    		if(H1<=n&&!(Max^(a[H1]+tot))) ++H1;//判断该蚯蚓属于哪个数组
    		else if(H2<=T2&&!(Max^(b[H2]+tot))) ++H2;
    		else ++H3;
    		LL s1=(1LL*Max*u)/v,s2=Max-s1;//砍断该蚯蚓
    		b[++T2]=max(s1,s2)-tot-q,c[++T3]=min(s1,s2)-tot-q;//将蚯蚓分别存入b[]数组和c[]数组,并将其长度减去当前的增长长度,因为刚砍断的蚯蚓长度不会增加
    	}
    	putchar('
    ');
    	merge(a,b,H1,n,H2,T2);//将a[],b[]数组归并
    	for(i=1;i<=n+T2-H1-H2+2;++i) s_[i]=s[i];
    	merge(s_,c,1,n+T2-H1-H2+2,H3,T3);将a[],b[]数组归并后得到的数组与c[]数组归并
    	for(i=t;i<=n+m;i+=t) write(s[i]+tot+q),putchar(' ');
    	return 0;
    }
    
  • 相关阅读:
    《图解算法》读书笔记(十)K最近邻算法
    《图解算法》读书笔记(九) 动态规划
    《图解算法》读书笔记(八) 贪婪算法
    Go 常用包之fmt、flag包(四)
    GO环境及初始化项目(二)
    nginx fpm 常见错误对比分析
    Ueditor富文本添加、编辑视频,视频不显示解决方案
    phpunit 测试
    mysql 主从并行复制(MTS)
    Explain执行计划详解
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/Luogu2827.html
Copyright © 2020-2023  润新知