zoukankan      html  css  js  c++  java
  • 【NOIP2016】蚯蚓(队列,单调性)

    题目不再重复叙述
    请参考:
    洛谷
    CJOJ

    题解

    先来说说非完美解法,也是我去年考场上的做法
    考虑一下每一只蚯蚓增加的长度,
    这个值并不需要每一次依次增加,
    用一个变量维护即可,每次取出蚯蚓就加上这个值,切断蚯蚓就减去这个值。
    接下来如何维护最大的蚯蚓,考虑使用一个堆来进行维护
    时间复杂度O(mlogm)显然超时(其实也就是常数巨大)

    现在,来考虑正解
    我们先来脑补几个显然成立的结论
    第一个:如果蚯蚓A长于蚯蚓B,一定是优先切蚯蚓A
    第二个:一只蚯蚓被切断后,两部分长度一定不会超过原长度
    第三个:如果蚯蚓A长于蚯蚓B,若干时间后,A还是长于B(A不被切)
    第四个:如果蚯蚓A长于蚯蚓B,A和B切断后,A的两段分别长于B的两段。

    那么,我们似乎发现了一点,单调性。
    看一看,先切的一定比后切的长。(显然成立呀)
    虽然不知道新切出来的部分和下一个切的部分谁更长,但是只需要1次比较就可以知道下一次应该切谁。(比较新切出来的长度和下一个本来应该要切的长度)

    那么,我们利用单调性来维护队列。(不需要优先队列了)

    首先维护所有初始的蚯蚓长度
    然后考虑到所有蚯蚓只会变成两段,并且一段长一段短。那么,再用两个队列维护长的那一段和短的那一段。

    现在,得到了3个队列,分别维护初始长度和切下来的两段的长度。
    根据上面几个很显然的结论,这三个队列都是满足由长到短的单调性的(初始长度就排个序来维护)
    那么,每次取出最长的蚯蚓就只需要考虑三个队列的首元素即可。
    这个时候的时间复杂度是O(N+M+NlogN)显然可以在时间范围内求解

    这道题目的关键就是 单调性,通过单调性解决掉优先队列,从而优化常数。

    最后注意几个小细节:
    不要提前算出来P的值,每次用U和V去计算,要不然会掉精度
    除的时候一定要强制换成longlong,要不可能会炸int
    INF值要开大一点,这样比较的时候才不会出问题。
    题目仔细读几遍,看题要仔细。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<cstdlib>
    #include<cmath>
    #include<algorithm>
    using namespace std;
    #define MAX 10000100
    #define INF 1000000000000000
    inline bool cmp(int a,int b)
    {
    	return a>b;
    }
    long long N,M,Q,U,V,T;
    long long q[3][MAX];
    long long h[3],t[3];
    long long cnt=0,now,fl,aa,bb;
    int main()
    {
    	scanf("%d%d%d%d%d%d",&N,&M,&Q,&U,&V,&T);
    	//P=U/V;
    	for(int i=1;i<=N;++i)
    		scanf("%d",&q[0][i]);
    	sort(&q[0][1],&q[0][N+1],cmp);
    	h[0]=h[1]=h[2]=1;t[0]=N;t[1]=t[2]=0;
    	for(int tt=1;tt<=M;++tt)
    	{
    		now=fl=-INF;
    		for(int i=0;i<3;++i)
    			if(h[i]<=t[i])
    			  if(now<q[i][h[i]])
    			  {
    				now=q[i][h[i]];
    				fl=i;
    			  }
    		h[fl]++;
    		now+=cnt;
    		aa=(1LL*now*U)/V;bb=now-aa;
    		if(aa>bb)swap(aa,bb);
    		q[1][++t[1]]=bb-cnt-Q;
    		q[2][++t[2]]=aa-cnt-Q;
    		cnt+=Q;
    		if(tt%T==0)
    			printf("%d ",now);
    	}
    	printf("
    ");
    	for(int tt=1;tt<=N+M;++tt)
    	{
    		 now=fl=-INF;
    		 for(int i=0;i<3;++i)
    			if(h[i]<=t[i])
    			  if(now<q[i][h[i]])
    			  {
    				now=q[i][h[i]];
    				fl=i;
    			  }
    		 if(tt%T==0)
    		 printf("%d ",now+cnt); 
    		 h[fl]++;
    	}
    	return 0;
    }
    
  • 相关阅读:
    DDoS deflate
    stm32串口
    王立平--GUI与GUILayout的差别
    DOM模型
    Android设计模式(十二)--抽象工厂模式
    Dynamics CRM 开启EmailRouter日志记录
    python in操作引发 TypeError
    为OLED屏添加GUI支持2:2D图形库
    Bloxorz I (poj 3322 水bfs)
    URAL 1823. Ideal Gas(数学啊 )
  • 原文地址:https://www.cnblogs.com/cjyyb/p/7282686.html
Copyright © 2011-2022 走看看