NOIP2016 D2T2 蚯蚓
其实是一道不是很难的模拟题,暴力好像可以拿80,AC的话要发现其中隐含的单调性
首先是一个小技巧,每次将所有蚯蚓的长度都+q肯定时间复杂度很大,那我们就想,其他所有的蚯蚓加,就相当于取出的蚯蚓减,再存储一下这是第几秒,输出或切蚯蚓的时候将存储的值加上秒数*q即可
然后就是题目中的单调性。对于两只蚯蚓x1,x2,设x1>x2且两者被切时间相差t,由题意显然x1比x2先被切。
那么我们可以列式算出x1和x2切出的蚯蚓到x2被切完那一秒的长度
x1切成的蚯蚓:[px1]+tq,x1-[px1]+tq(取整符号打不出来用方括号[]代替)
x2切成的蚯蚓:[p(x2+tq)]=[px2+ptq],x2-[p(x2+tq)]=x2-[px2+ptq]
tq>ptq且x1>x2,所以[px1]+tq>[p(x2+tq)]。证后半部分时可先去掉取整符号看,上面是(1-p)x1+tq,下面是(1-p)x2-ptq,因为x1>x2,tq>-ptq,所以上面显然大于下面,加上取整后误差不大于1,所以x1-[px1]+tq>x2-[p(x1+tq)]
这样我们就证明了先被切的蚯蚓切成的蚯蚓长度一定大于后被切的蚯蚓切成的蚯蚓长度(按顺序)
然后我们就可以用三个数组来存放,第一个数组表示原蚯蚓,从大到小排序一遍即可,然后每次切的蚯蚓放在第二个数组和第三个数组,这样每个数组都一定是从大到小的,每次取最大的切就可以了(其实就相当于手写优先队列,只不过插入的元素是有序的而已)
最后再把三个数组中的剩余元素放在一起排序一下即可(不要用STL优先队列!会超时!)
贴个代码:
1 #include<cstdio> 2 #include<algorithm> 3 #include<climits> 4 #include<cmath> 5 using namespace std; 6 int chong[3][8000001],left[3]={1,1,1},right[3];//存储三堆蚯蚓及它们的左右位置 7 int ans[8000001],tot;//存放答案并排序的数组 8 inline int front(int x)//取第x堆的队首元素 9 { 10 if(left[x]>right[x]) 11 return INT_MIN; 12 else 13 return chong[x][left[x]]; 14 } 15 bool comp(int a,int b) 16 { 17 return a>b; 18 } 19 int main() 20 { 21 int n,m,q,u,v,t,base=0;//base是当前已进行的累加和 22 scanf("%d%d%d%d%d%d",&n,&m,&q,&u,&v,&t); 23 right[0]=n; 24 for(int i=1;i<=n;i++) 25 scanf("%d",&chong[0][i]); 26 sort(chong[0]+1,chong[0]+1+n,comp); 27 for(int i=1;i<=m;i++) 28 { 29 int flag=0;//标记哪一堆的蚯蚓最大 30 int a=front(0),b=front(1),c=front(2); 31 if(c>=b&&c>=a) 32 flag=2; 33 else if(b>=a&&b>=c) 34 flag=1; 35 a=chong[flag][left[flag]]+base;//最大蚯蚓实际长度 36 b=(int)((long long)u*a/(double)v); 37 c=a-b; 38 b-=base+q,c-=base+q;//其他的加相当于取出的减 39 left[flag]++;//取蚯蚓 40 chong[1][++right[1]]=b;//放蚯蚓 41 chong[2][++right[2]]=c; 42 if(i%t==0)//被t整除时输出长度 43 printf("%d ",a); 44 base+=q;//每次加q 45 } 46 printf("\n"); 47 for(int i=0;i<3;i++)//将剩下的蚯蚓排列 48 for(int j=left[i];j<=right[i];j++) 49 ans[++tot]=chong[i][j]; 50 sort(ans+1,ans+1+tot,comp); 51 for(int i=1;i<=tot;i++) 52 if(i%t==0) 53 printf("%d ",ans[i]+base); 54 printf("\n"); 55 return 0; 56 }
两个注意事项:
1、要做长度标记(每个时刻蚯蚓伸长的总长度,切和输出时都要加上!)
2、判断三者大小关系时一定要用大于等于!且注意关系,比如c最大是c>=a&&c>=b而不是c>=b&&b>=a(第一次就因为这个WA成35分)
3、找三个队列中最大元素不能不判断队列是否为空,因为前面我们用减代替加,会有负数,初始化的元素为0会让我们取到,所以我直接写了一个取队首元素函数,当队列为空的时候就返回负无穷大