Codeforces 1042C Array Product
题目的大致意思是给一个数组a,大小为n(可能有正数,负数和0可以进行如下两种操作:
1.选择两个位置i,j(i<j)然后 a[j] *= a[i],把a[i]删除。 i
2.选择一个位置i,把a[i]删除a[x]
操作2至多只能用一次。
最终结果是通过这两个操作,n-1次操作,把数组中的数字处理到只剩一个。并且要求使最后的这个数字尽量大。
输出操作的序列。
1 i j 表示操作1
2 i 表示操作2
首先很容易想到是首先把数组中的0和负数给除掉。
如果有偶数个负数,那就不用管他了,因为几次相乘后是正数
如果有奇数个负数,那就把负数中最大的负数的位置记下来,用操作2把它删了
0怎么办呢,无论是奇数个0还是偶数个0,我们都可以通过操作1和操作2把他们给删了。
同样,我们可以把奇数个负数的情况里面最大的负数同0一起删除。
这样数组中最后剩下的都是正数了,就可以一个一个的乘了.
同时我们要考虑到数组全为0的情况,这样最后就不要输出操作2了
#include<iostream> #include<vector> using namespace std;const int N = 2e5 + 5;int n,a[N],num,maxn = -2e9,pos,vis[N]; int main(){ cin >> n; for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); if (a[i] == 0) vis[i]=1 ; if (a[i] < 0) { num++; if (a[i]>maxn) maxn = a[i],pos = i; } } if (num & 1) vis[pos] = 1;//把最大的负数的位置同0一起删除 int pre = 0,cnt=0; for (int i = 1; i <= n; i++) { if (vis[i]) { if(pre) printf("1 %d %d\n", pre, i),cnt++; pre = i; } } if (pre&&cnt<n-1) printf("2 %d\n", pre); //cnt防止数组全为0 pre = 0; for (int i = 1; i <= n; i++) { if (!vis[i]) { if (pre) printf("1 %d %d\n", pre, i); pre = i; } } return 0; }
(1