标签:
题目:
http://acm.hdu.edu.cn/showproblem.php?pid=5596
这道题可以很巧妙的用O(n)的时间复杂度做出来的。首先,当我们用一个数组c存储gt发功的时间时,以该时间为下标之前的b值都会加1,所以可以用c[i] += c[i-1],以获得当前节点之前,已累计法功多少次了,然后c[y]-c[x](y>x)就是以x为下标的gt,到y时间时,通过发功增加的量。
至于为什么要倒着处理呢,因为我们是要去掉小的元素,这样,我们只要从后往前,保存最大的元素,只要存在小于最大元素的,该元素就可以去掉了。
还有,max0、max1分别是1组的最大值和0组的最大值,以gt[i].b-c[i-1]-max0这个式子为例,我们这里假设x<y,max0 = gt[y].b-c[y-1],所以前面那个式子就可以化成gt[x].b-c[x-1]-gt[y].b-c[y-1] = gt[x].b-gt[y].b+c[y-1]-c[x-1],由我们前面的推导,c[y-1]-c[x-1]就是gt[x].b增加的量,这个值加上gt[x].b,如果减去gt[y].b小于0的话,说明该gt是要去掉的,同时要更新max1的值,以为此时处理的是0组的情况,保存最大的。
1 #include<stdio.h> 2 #include<string.h> 3 #include<algorithm> 4 #define maxn 50005 5 #define inf 0x3f3f3f3f 6 using namespace std; 7 struct node{ 8 int group; 9 int b; 10 }; 11 node gt[maxn]; 12 int c[maxn]; 13 int main(){ 14 int t; 15 scanf("%d",&t); 16 while(t--){ 17 int n,m; 18 memset(c,0,sizeof(c)); 19 scanf("%d%d",&n,&m); 20 for(int i = 1;i<=n;i++){ 21 scanf("%d%d",>[i].group,>[i].b); 22 } 23 for(int i = 1;i<=m;i++){ 24 int temp; 25 scanf("%d",&temp); 26 c[temp]++; 27 } 28 for(int i = 1;i<=n;i++){ 29 c[i] += c[i-1]; 30 } 31 int ans = n; 32 int max0 = -inf,max1 = -inf; 33 for(int i = n;i>0;i--){ 34 if(gt[i].group){ 35 if(gt[i].b-c[i-1]-max0<0) 36 ans--; 37 max1 = max(max1,gt[i].b-c[i-1]); 38 }else{ 39 if(gt[i].b-c[i-1]-max1<0) 40 ans--; 41 max0 = max(max0,gt[i].b-c[i-1]); 42 } 43 } 44 printf("%d\n",ans); 45 } 46 return 0; 47 }
标签:
原文地址:http://www.cnblogs.com/zqy123/p/5049442.html