[bzoj4977]跳伞求生<贪心>
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=4977
这是八月月赛的一道题,月赛的时候和同学讨论了一下,最后由一位叫二哥的大佬率先AC,用的是贪心(学不来学不来),虽然正解貌似是dp(不清楚);
看了看这道题的数据范围,我并没有打算怎么去优化,直接暴力的处理加上贪心操作,我一开始用的是优先队列,结果数据一大结果就是负数(还有这操作???),后来我把优先队列改成了几个数组,然后多次快排(毕竟数据范围不大),终于AC了;
这个贪心用到了一个结论,就是在确定的敌人和队友之间,交换彼此的对手,总值不变,意思是:
原本的配对方案是队友1打敌人1,队友2打敌人3,然后假如队友1,2交换,总值不变,用式子来说就是:
ans=(a1-b1+c1)+(a2-b2+c2)=(a2-b1+c1)+(a1-b2+c2);
具体步骤是:
1.首先存下ci-bi的值val,然后按照val从大到小排序,并让ai按照从大到小排序,同时开一个桶(本人的方法,没有优化,听起来可能比较复杂)
2.然后按val大小找,如果当前敌人可以被打死,那就意味这我们需要一个我方队友,tot++(建议这时候找刚刚比b大的a)
3.然后找前tot大的人作为我方人员,与敌方参战的tot人配对,这时候我开了两个数组,分别存,我方参战和敌方参战人员,并按从小到大排序
4.接着会用到我们的结论(即上文红字),所以我们要删除人,我们把我方ai最小和敌人val(ci-bi)最小的相加,如果为负就删除,不然留下他们就是负贡献(至于为什么删和为什么可以删掉,想想结论,并假设3步骤选出来的人就固定且选出来的每个队友都可以打一个任意选出来的敌人)
5.最后把留下的贡献为正的相加即可
代码我先给一个优先队列的,可以A一部分(并没有什么卵用),但是希望大佬能为我解释一下,为什么数据大了就会成负的?
第一个代码是不能AC的代码!!
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdlib> 6 #include<cmath> 7 #include<queue> 8 #include<stack> 9 #define maxn 100005 10 using namespace std; 11 12 struct node{ 13 int b,c,val; 14 }e[maxn]; 15 16 int comp(const void*a,const void*d) 17 { 18 if((*(struct node*)a).val==(*(struct node*)d).val) 19 return (*(struct node*)a).b>(*(struct node*)d).b?1:-1; 20 return (*(struct node*)a).val>(*(struct node*)d).val?-1:1; 21 } 22 23 int n,m,gun[maxn],maxx; 24 long long sc; 25 26 priority_queue<int>q; 27 priority_queue<int,vector<int>,greater<int> >q1; 28 priority_queue<int,vector<int>,greater<int> >q2; 29 30 int main() 31 { 32 scanf("%d%d",&n,&m); 33 for(int i=1;i<=n;i++) 34 { 35 int x; 36 scanf("%d",&x); 37 maxx=max(maxx,x); 38 //if(gun[x]==0)q.push(x); 39 q.push(x); 40 gun[x]++;//一个桶来存各种子弹人数,每次选距离消耗最近的 41 } 42 for(int i=1;i<=m;i++) 43 { 44 int x,y; 45 scanf("%d%d",&x,&y); 46 e[i].b=x;e[i].c=y; 47 e[i].val=y-x; 48 } 49 e[0].b=0x3f3f3f;e[0].val=0x3f3f3f; 50 qsort(e,m+1,sizeof(e[0]),comp); 51 int tot=0; 52 for(int i=1;i<=m;i++) 53 { 54 if(e[i].b<maxx){ 55 for(int j=e[i].b+1;j<=maxx;j++) 56 { 57 if(gun[j]>0) 58 { 59 gun[j]--; 60 tot++; 61 q2.push(e[i].val); 62 break; 63 } 64 65 } 66 } 67 68 } 69 for(int i=1;i<=tot;i++) 70 { 71 int dd=q.top(); 72 q1.push(q.top()); 73 q.pop(); 74 } 75 for(int i=1;i<=tot;i++) 76 { 77 int x,y; 78 x=q1.top();y=q2.top(); 79 if(x+y<=0){ 80 q1.pop();q2.pop(); 81 } 82 else break; 83 } 84 int yy=q1.size(); 85 for(int i=1;i<=yy;i++) 86 { 87 sc+=q1.top()+q2.top(); 88 q1.pop();q2.pop(); 89 } 90 printf("%lld",sc); 91 } 92
接下来是用数组和快排代替优先队列的(排版较暴力)
1 #include<cstdio> 2 #include<cstring> 3 #include<iostream> 4 #include<algorithm> 5 #include<cstdlib> 6 #include<cmath> 7 #include<queue> 8 #include<stack> 9 #define maxn 100005 10 using namespace std; 11 12 struct node{ 13 int b,c,val; 14 }e[maxn]; 15 16 int comp(const void*a,const void*d) 17 { 18 if((*(struct node*)a).val==(*(struct node*)d).val) 19 return (*(struct node*)a).b>(*(struct node*)d).b?1:-1; 20 return (*(struct node*)a).val>(*(struct node*)d).val?-1:1; 21 } 22 23 int cmp1(const void*a,const void*d) 24 { 25 return (*(int*)a)>(*(int*)d)?-1:1; 26 }//从大到小 27 28 int cmp2(const void*a,const void*d) 29 { 30 return (*(int*)a)>(*(int*)d)?1:-1; 31 }//从小到大 32 33 int n,m,gun[maxn],maxx,num[maxn],nu[maxn]; 34 long long sc; 35 36 int main() 37 { 38 /* freopen("in.in","r",stdin); 39 freopen("my.out","w",stdout);*/ 40 scanf("%d%d",&n,&m); 41 for(int i=1;i<=n;i++) 42 { 43 int x; 44 scanf("%d",&x); 45 maxx=max(maxx,x); 46 num[i]=x; 47 gun[x]++;//一个桶来存各种子弹人数,每次选距离消耗最近的 48 } 49 num[0]=0x3f3f3f; 50 qsort(num,n+1,sizeof(int),cmp1); 51 for(int i=1;i<=m;i++) 52 { 53 int x,y; 54 scanf("%d%d",&x,&y); 55 e[i].b=x;e[i].c=y; 56 e[i].val=y-x; 57 } 58 e[0].b=0x3f3f3f;e[0].val=0x3f3f3f; 59 qsort(e,m+1,sizeof(e[0]),comp); 60 int tot=0; 61 for(int i=1;i<=m;i++) 62 { 63 if(e[i].b<maxx){ 64 for(int j=e[i].b+1;j<=maxx;j++) 65 { 66 if(gun[j]>0) 67 { 68 gun[j]--; 69 tot++; 70 nu[tot]=e[i].val; 71 break; 72 } 73 74 } 75 } 76 77 } 78 num[0]=nu[0]=-0x3f3f3f; 79 qsort(num,tot+1,sizeof(int),cmp2); 80 qsort(nu ,tot+1,sizeof(int),cmp2); 81 for(int i=1;i<=tot;i++) 82 { 83 if(num[i]+nu[i]<=0) 84 { 85 continue; 86 }else{ 87 sc+=num[i]+nu[i]; 88 } 89 } 90 printf("%lld",sc); 91 92 } 93