Maximum Sum
你有一个由 n n n 个整数组成的数组 a a a 。
你要对它进行 k k k 次操作。在一次操作中,你选择了数组 a a a 中任意连续的子数组(可能是空的),并将该子数组的和插入数组 a a a 的任意位置。(可能为空),并在数组的任意位置插入该子数组的和。
你的任务是找出经过 k k k 次操作后数组的最大和。
由于这个数字可能非常大,请输出答案的模数 1 0 9 + 7 10^9+7 109+7 。
提示:数字 x m o d u l o p x\ modulo\ p x modulo p 的余数是存在整数 q q q 和 x = p ⋅ q + y x=p⋅q+y x=p⋅q+y 的最小非负数 y y y 。
输入
每个测试由多个测试用例组成。第一行包含一个整数
t
(
1
≤
t
≤
1
0
4
)
t ( 1≤t≤10^4 )
t(1≤t≤104) - 测试用例数。然后是测试用例的描述。
每个测试用例的第一行包含两个整数 n n n 和 k ( 1 ≤ n , k ≤ 2 ⋅ 1 0 5 ) k ( 1≤n,k≤2⋅10^5 ) k(1≤n,k≤2⋅105) - 分别是数组的长度 a a a 和操作次数。
每个测试用例的第二行包含 n n n 个整数 a 1 , a 2 , … , a n ( − 1 0 9 ≤ a i ≤ 1 0 9 ) a_1,a_2,…,a_n ( −10^9≤a_i≤10^9 ) a1,a2,…,an(−109≤ai≤109)。
保证所有测试用例中 n n n 和 k k k 的值之和不超过 2 ⋅ 1 0 5 2⋅10^5 2⋅105 。
输出
对于每个测试,输出一个整数 - 经过
k
k
k 次运算
m
o
d
u
l
o
1
0
9
+
7
modulo\ 10^9+7
modulo 109+7 后得到的数组最大和。
如果我们在第一步找到了最大子段和,然后我们就一定可以将这个和加到最大子段和的同一个位置,这样就一直维持了最大的一段子段和。
那么如果
k
=
1
k = 1
k=1,就可以输出原数组的和加上这个子段和就可以。
如果
k
>
1
k > 1
k>1,每次都是将操作过的子段和重新加入,那么第一次操作子段和就变为了
2
x
2x
2x,数组的总和要加入
x
x
x ,第二次就变为了
4
x
4x
4x,数组的总和要加上
3
x
3x
3x,所以操作
k
k
k 次之后,数组的总和就变为了原数组的和加
上
2
k
2^{k}
2k 的最大子段和减去一个最大子段和。
当然本题的取模操作比较关键,要注意不出现任何溢出的情况。
CODE:
#include <bits/stdc++.h>
using namespace std;
const int N = 2e5 + 10;
const int mod = 1e9+7;
#define ll long long
int a[N];
int n;
int k;
ll qmi(int a,int k,int p){
ll res = 1;
while(k){
if(k & 1)res = (ll)res * a % p;
k >>= 1;
a = (ll)a * a % p;
}
return res;
}
void solve()
{
cin >> n >> k;
long long sum = 0;
for(int i = 1;i <= n;i++){
cin >> a[i];
sum += a[i];
sum %= mod;
}
ll res = 0;
ll now = 0;
for(int i = 1;i <= n;i++){
if(now > 0) now += a[i];
else now = a[i];
if(now > res)res = now;
}
res = max(res,0ll);
res = res % mod;
if(k == 1){
cout << ((sum + res)%mod + mod)%mod << endl;
}else {
cout << (sum + (ll)qmi(2,k,mod)*res - res + mod) % mod << endl;
}
}
int main()
{
int T;
cin >> T;
while (T--)
{
solve();
}
return 0;
}
最大子段和
在这里使用了DP的方法求最大子段和,这里 res 是总体的最大子段和,now 是前i项的最大子段和,下面给出维护了最大子段和起点和终点的代码。
CODE1:
//f[i]为前i个元素里面的最大子段和
for(i=1;i<=n;i++){
cin>>a[i];
if(i==1) f[i]=a[i];
else f[i]=max(a[i],f[i-1]+a[i]);
ans=max(ans,f[i]);
}
for(i=1;i<=n;i++){
cin>>a;
if(i==1) b=a;
else b=max(a,a+b);
ans=max(ans,b);
}
CODE2:
for (int i = 1; i <= n; i++)
{
if (now > 0)
now += a[i];
else
{
now = a[i];
begin = i;
}
if (now > res)
{
res = now;
end = i;
}
}