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
", pre, i),cnt++;
            pre = i;
        }
    }
    if (pre&&cnt<n-1) printf("2 %d
", pre); //cnt防止数组全为0
    pre = 0;
    for (int i = 1; i <= n; i++)
    {
        if (!vis[i])
        {
            if (pre) printf("1 %d %d
", pre, i);
            pre = i;
        }
    }
    return 0;
}

(1

原文地址:https://www.cnblogs.com/xiaoguapi/p/10446235.html