[NOIP2016]蚯蚓(单调性乱搞)

题目

链接

思路

最简单的思路肯定就是直接用堆维护,每次取最大的那一个,切成两截扔回堆里面(至于所有蚯蚓加上(q),可以看做是新生成的蚯蚓减去(time*q),最后再加回去即可,其中(time)即第几秒),然而这样子做是(O(n+m)log(n+m))的,过不了

分析后可以发现单调性,即如果把切出来的两部分分别放到一个数组里面,它们分别单调递减

证明也很简单,设先切的蚯蚓长度为(len1),后切的在切(len1)的这个时候长度为(len2),那么有(len2)(leq)(len1),它们长度不增长的时间仅仅是切的时候,即它们的增加量相等,那么有(len2+c)(leq)(len1+c)恒成立

所以把它们分成三个数组(队列),分别存初始蚯蚓、(切了一刀之后)第一节、第二节,对初始蚯蚓排序可以使第一个数组从大到小排序,将后切出来的蚯蚓放到队列后面可以使得这两个数组也满足从大到小排序,取最大的蚯蚓即从三个队列的队头取最大值

对于第二问,将三个队列进行归并排序即可

时间复杂度为(O(nlogn+m))

#include<bits/stdc++.h>
#define N 100005
#define M 7000005
using namespace std;
int n,m,q,u,v,t;
int a[3][M],top[3];
int b[N+M],c[N+M];

template <class T>
void read(T &x)
{
	char c;int sign=1;
	while((c=getchar())>'9'||c<'0') if(c=='-') sign=-1; x=c-48;
	while((c=getchar())>='0'&&c<='9') x=x*10+c-48; x*=sign;
}
bool cmp(int a,int b) {return a>b;} 
int main()
{
	read(n);read(m);read(q);
	read(u);read(v);read(t);
	for(register int i=1;i<=n;++i) read(a[0][i]);
	a[0][0]=n;
	top[0]=top[1]=top[2]=1;
	sort(a[0]+1,a[0]+n+1,cmp);
	for(register int i=1;i<=m;++i)
	{
		int maxx=(top[0]>n);
		if(a[maxx][top[maxx]]<a[1][top[1]]&&top[1]<=a[1][0]) maxx=1;
		if(a[maxx][top[maxx]]<a[2][top[2]]&&top[2]<=a[2][0]) maxx=2;
		int len=a[maxx][top[maxx]++]+(i-1)*q;
		int L=(long long)u*len/v;
		int R=len-L;
		a[1][++a[1][0]]=L-q*i;
		a[2][++a[2][0]]=R-q*i;
		if(i%t==0) printf("%d ",len);
	}
	printf("
");
	int l=top[0],r=top[1];
	while(l<=a[0][0]&&r<=a[1][0])
	{
		if(a[0][l]>a[1][r]) b[++b[0]]=a[0][l++];
		else b[++b[0]]=a[1][r++];
	}
	while(l<=a[0][0]) b[++b[0]]=a[0][l++];
	while(r<=a[1][0]) b[++b[0]]=a[1][r++];
	l=1;r=top[2];
	while(l<=b[0]&&r<=a[2][0])
	{
		if(b[l]>a[2][r]) c[++c[0]]=b[l++];
		else c[++c[0]]=a[2][r++];
	}
	while(l<=b[0]) c[++c[0]]=b[l++];
	while(r<=a[2][0]) c[++c[0]]=a[2][r++];
	for(int i=t;i<=n+m;i+=t) printf("%d ",c[i]+m*q);
	printf("
");
	return 0;
}
原文地址:https://www.cnblogs.com/Chtholly/p/11347779.html