http://codeforces.com/contest/1042/problem/C
给你一个有n个元素序列,有两个操作:
1,选取a[i]和a[j],删除a[i],将$a[i]*a[j]$赋值给a[j]
2,任意选定一个数删除(只能做一次).
打印操作,让最后剩下的数最大。
题意还是比较好理解的。
我们可以想到我们需要先把所有的0,合为一个,然后判断负数两两配对是否多出一个(!%2),两两配对后,两个负数相乘变为正数,正数当然越乘越大。
如果多出一个来,因为要让乘积最大,那么对于负数而言,我们需要删掉最大的负数,将这个最大的负数和0进行1操作,然后删除0(删除两个数的乘积)。
如果负数为偶数,那么我们直接把0的位置,删掉就好了,将剩下的的乘起来。
这样大体的思想就出来了,要注意一大堆细节问题:
1.如果全是0,那么我们只进行1操作(n-1)次就好,做完return 0;
2.没有0,。
3.没有负数。
4.没有正数。
上边的四种情况在代码中都有体现:
#include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <cmath> using namespace std; int cnt,cnt1,cnt2,n,x; struct ahah { int x,pos; } a[200006],b[200006],c[200006]; bool cmp(ahah a,ahah b){ return abs(a.x)<abs(b.x); } int main() { scanf("%d",&n); for(int i=1; i<=n; i++) { scanf("%d",&x); if(x==0)c[++cnt].pos=i; if(x<0)a[++cnt1].x=x,a[cnt1].pos=i; if(x>0)b[++cnt2].x=x,b[cnt2].pos=i; } sort(a+1,a+1+cnt1,cmp); sort(b+1,b+1+cnt2,cmp); int v=-1; if(cnt!=0) { v=c[1].pos; for(int i=2; i<=cnt; i++) { printf("1 %d %d ",v,c[i].pos); v=c[i].pos; } } if(cnt==n)return 0; if(cnt1%2==0) { if(v!=-1)printf("2 %d ",v),v=-1; if(cnt1!=0) { if(v==-1)v=a[1].pos; else printf("1 %d %d ",v,a[1].pos),v=a[1].pos; for(int i=2; i<=cnt1; i++) { printf("1 %d %d ",v,a[i].pos); v=a[i].pos; } } if(cnt2!=0) { if(v==-1)v=b[1].pos; else printf("1 %d %d ",v,b[1].pos),v=b[1].pos; for(int i=2; i<=cnt2; i++) { printf("1 %d %d ",v,b[i].pos); v=b[i].pos; } } } else { if(v==-1)v=a[1].pos; else printf("1 %d %d ",v,a[1].pos),v=a[1].pos; if(cnt+1!=n)printf("2 %d ",v),v=-1; else return 0; if(cnt1>1) { v=a[2].pos; for(int i=3; i<=cnt1; i++) { printf("1 %d %d ",v,a[i].pos); v=a[i].pos; } } if(cnt2>0) { if(v==-1)v=b[1].pos; else printf("1 %d %d ",v,b[1].pos),v=b[1].pos; for(int i=2; i<=cnt2; i++) { printf("1 %d %d ",v,b[i].pos); v=b[i].pos; } } } }