CODECHEF:Change the Signs(dp & 思维)

You are given a sequence of integers A1,A2,,ANA1,A2,…,AN.

You should choose an arbitrary (possibly empty) subsequence of AA and multiply each element of this subsequence by 1−1. The resulting sequence should satisfy the following condition: the sum of elements of any contiguous subsequence with length greater than 1 is strictly positive.

You should minimise the sum of elements of the resulting sequence. Find one such sequence with the minimum possible sum.

Input

  • The first line of the input contains a single integer TT denoting the number of test cases. The description of TT test cases follows.
  • The first line of each test case contains a single integer NN.
  • The second line contains NN space-separated integers A1,A2,,ANA1,A2,…,AN.

Output

For each test case, print a single line containing NN space-separated integers B1,B2,,BNB1,B2,…,BN. For each valid iiBiBi must be equal to either AiAi (the sign of this element did not change) or Ai−Ai (the sign of this element changed).

If there is more than one answer, you may output any one.

Constraints

  • 1T1051≤T≤105
  • 2N1052≤N≤105
  • 1Ai1091≤Ai≤109 for each valid ii
  • the sum of NN for all test cases does not exceed 51055⋅105

Subtasks

Subtask #1 (20 points):

  • 1T2001≤T≤200
  • 2N102≤N≤10

Subtask #2 (30 points):

  • 1T1,0001≤T≤1,000
  • N2,000N≤2,000

Subtask #3 (50 points): original constraints

Example Input

4
4
4 3 1 2
6
1 2 2 1 3 1
5
10 1 2 10 5
4
1 2 1 2

Example Output

4 3 -1 2
-1 2 2 -1 3 -1
10 -1 2 10 -5
1 2 -1 2

Explanation

Example case 1: If we change only the sign of A3A3, we get a sequence {4,3,1,2}{4,3,−1,2}with sum 88. This sequence is valid because the sums of all its contiguous subsequences with length >1>1 are positive. (For example, the sum of elements of the contiguous subsequence {A3,A4}{A3,A4} equals 1+2=1>0−1+2=1>0.)

There are only two valid sequences {4,3,1,2}{4,3,−1,2} and {4,3,1,2}{4,3,1,2} with sums 88 and 1010respectively, so this sequence has the smallest possible sum.

For instance, the sequence {4,3,1,2}{4,−3,1,2} isn't valid, because the sum of {A2,A3,A4}{A2,A3,A4}equals 3+1+2=00−3+1+2=0≤0.


题意:给N个正数,可以在其中任意一些数加上负号,使得最终的数组任意长度>1的连续子串和为正数,并且数组总和要最小,输出最终的数组。

思路:首先显然不能两个负数并列,然后显然如果最终的数组满足以下情况:长度为2的串和为正数、长度为3的串和为正数。那么其他长度的串和就为正数。反证一下:如果存在长度为4的串和为非正数,那么显然第1个和第4个数都是负数,显然第2个和第3数是正数,由于满足上述的条件,那么这个串总和就应该为正数。  因此dp[i][j],j<8表示以i结尾的连续三个数的正负状态,取最小值即可。

# include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5+30;
typedef long long LL;
LL a[maxn], dp[maxn][8], ok[maxn][8];
const LL inf = 0x3f3f3f3f3f3f3f3f;
bool ans[maxn];
int f(int x){return x?1:-1;}
void dfs(int cur, int num)
{
    if(cur == 2) ans[cur]=num&1, ans[cur-1]=num>>1;
    else
    {
        ans[cur] = num&1;
        if(dp[cur][num|4] < dp[cur][num]) dfs(cur-1, num>>1|2);
        else dfs(cur-1, num>>1);
    }
}
int main()
{
    int t, n;
    scanf("%d",&t);
    while(t--)
    {
        scanf("%d",&n);
        for(int i=1; i<=n; ++i)
            scanf("%lld",&a[i]);
        if(n == 2)
        {
            if(a[1] == a[2]) printf("%lld %lld\n",a[1],a[2]);
            else if(a[1] > a[2]) printf("%lld %lld\n",a[1],-a[2]);
            else printf("%lld %lld\n",-a[1],a[2]);
            continue;
        }
        for(int i=0; i<8; ++i)
        {
            if(i>>2) dp[2][i] = inf, ok[2][i] = 0;
            else
            {
                LL tmp1 = a[1]*f(i>>1) + a[2]*f(i&1);
                if(tmp1 > 0) ok[2][i] = 1,dp[2][i] = tmp1;
                else dp[2][i] = inf, ok[2][i] = 0;
            }
        }
        for(int i=3; i<=n; ++i)
        {
            for(int j=0; j<8; ++j)
            {
                dp[i][j] = inf;
                ok[i][j] = 0;
                LL tmp1 = a[i-2]*f(j>>2) + a[i-1]*f(j>>1&1) + a[i]*f(j&1);
                LL tmp2 = a[i-2]*f(j>>2) + a[i-1]*f(j>>1&1);
                LL tmp3 = a[i-1]*f(j>>1&1) + a[i]*f(j&1);
                if(tmp1>0 && tmp2>0 && tmp3>0)
                {
                    ok[i][j] = 1;
                    if(ok[i-1][j>>1]) dp[i][j] = min(dp[i][j], dp[i-1][j>>1]+a[i]*f(j&1));
                    if(ok[i-1][j>>1|4]) dp[i][j] = min(dp[i][j], dp[i-1][j>>1|4]+a[i]*f(j&1));
                }
            }
        }
        LL imin = 1e18;
        for(int i=0; i<8; ++i)
            if(ok[n][i] && dp[n][i]<imin) imin = dp[n][i];
        for(int i=0; i<8; ++i)
        {
            if(dp[n][i] == imin)
            {
                ans[n] = i&1;
                dfs(n-1, i>>1);
            }
        }
        for(int i=1; i<=n; ++i)
            printf("%lld%c",ans[i]?a[i]:-a[i],i==n?'\n':' ');
    }
    return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值