E.Negatives and Positives
题意:给你一串数字,你可以选择任意位置将当前位置和下一个位置的符号都变成与原来不一样,问你可以得到的最大的和是多少?
贪心:
分析:发现从前往后扫,如果是负的话只需要直接变号,这样得到的除了最后一个不一定是正数以外的所有数字一定是正数,最后如果是一个负数的话我们发现负号传播给当前串中绝对值最小的(也有可能是自己)就可以了
代码:
#include<bits/stdc++.h>
using namespace std;
int T;
int n;
typedef long long ll;
ll res,tem;
void solve()
{
res = 0;
tem = 0x7fffffff;
cin>>n;
vector<ll>a(n+10,0);
for(int i=1;i<=n;i++)
{
cin>>a[i];
tem = min(tem,llabs(a[i]));
}
for(int i=1;i<=n-1;i++)
{
if(a[i]<0)
{
a[i+1] = -a[i+1];
a[i] = -a[i];
}
res+=a[i];
}
if(a[n]<0)res = max(res-a[n]-2*tem,res+a[n]);
else res+=a[n];
cout<<res<<endl;
}
int main()
{
cin>>T;
while(T--)
solve();
}
Dp:
分析:
发现可以对前缀和进行Dp
Dp[i][j] i为 取值为[0,1] j取值为[1,n]:
每个位置可以进行的选择有两中国,要么是选择改变符号,要么选择不改变符号 (最后一个位置不可主动选择改变)其中0表示选择不改变符号,1表示选择改变符号
递推方程是:
dp[0][i] = max(dp[0][i-1]+a[i],dp[1][i-1]-a[i])
dp[1][i] = max(dp[0][i-1]-a[i],dp[1][i-1]+a[i])
初始状态:
dp[0][1] = x;
dp[1][1] = x;
一定注意边界,很容易恶心人
结果是dp[0][n]
代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
int T;
void solve()
{
int n;
cin>>n;
vector<vector<ll>>dp(2,vector<ll>(n+10));
vector<ll>a(n+10,0);
for(int i=1;i<=n;i++)
cin>>a[i];
dp[0][1] = a[1];
dp[1][1] = -a[1];
for(int i=2;i<=n;i++)
{
dp[0][i] = max(dp[0][i-1] + a[i],dp[1][i-1]-a[i]);
dp[1][i] = max(dp[0][i-1] - a[i],dp[1][i-1]+a[i]);
}
cout<<dp[0][n]<<endl;
}
int main()
{
cin>>T;
while(T--)
solve();
}