做了牛客哈理工的一套训练赛的题目,真的是知识欠缺严重啊,首先补一下这个最大和最小子串和的问题。
求一个数组中连续一段和的最大值和最小值问题
最大值函数代码
ll maxsum() //最大和
{
ll sum=0,maxx=-2147483647;
for(int i=0;i<n;i++)
{
sum += a[i];
if(sum > maxx)
maxx = sum;
if(sum < 0)
sum = 0;
}
return maxx;
}
最小值函数代码
int minsum() //最小和
{
int sum1=0,minn=2147483647;
for(int i=0;i<n;i++)
{
sum += num[i];
if(sum < minn)
minn = sum;
if(sum > 0)
sum = 0;
}
return minn;
}
原题链接:寂寞如雪
原题内容:
题目描述
格雷福斯因为由于不知名力量失去了战斗力,需要启明小朋友为他点烟才能恢复力量,格雷福斯需要的烟是一种名为寂寞如雪的烟,启明小朋友需要截取一段连续的寂寞制作成寂寞如雪帮助格雷福斯恢复力量。
寂寞可以看做一段连续的01字符串,其中0表示落寞,1表示孤独,格雷福斯只需要孤独不需要落寞。因为格雷福斯只有两发子弹,所以格雷福斯不喜欢偶数。多个连续出现的孤独可以看做一段孤独,寂寞如雪中第奇数段长度为n的孤独可以为格雷福斯提供n2点力量,第偶数段长度为n的孤独会减少格雷福斯n2点力量,启明小朋友不知道格雷福斯最多可以恢复多少点力量,所以向你求助。
输入描述:
输入共一行,一个长度不超过1e6的字符串。
输出描述:
一个整数,最多可以恢复的力量。
输入:
111011001111100111
输出:
30
样例解释:
截取1110110011111,获得的力量为3^2-2^2+5^2=30
备注:
连续的1在计算时会被算成一段,不可以拆成多段
第奇数段还是第偶数段是看截取后字符串中的位置
题解:先对01字符串进行统计,统计出连续的1的个数分别是多少,因为截取之后,该段要么为第奇数段要么为第偶数段,所有该段的值要么为正数要么为负数,一共这两种情况,只需要计算这两种情况中的最大和最小值即可
AC代码如下:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 1e6+10;
ll a[N];//第一段为正
ll af[N];//第一段为负
ll n;
ll maxsum() //最大和
{
ll sum=0,maxx=-2147483647;
for(int i=0;i<n;i++)
{
sum += a[i];
if(sum > maxx)
maxx = sum;
if(sum < 0)
sum = 0;
}
return maxx;
}
ll maxsumf() //最大和
{
ll sum=0,maxx=-2147483647;
for(int i=0;i<n;i++)
{
sum += af[i];
if(sum > maxx)
maxx = sum;
if(sum < 0)
sum = 0;
}
return maxx;
}
int main()
{
string s;
cin >> s;
int cnt = 0;
bool flag = 0;
for(int i = 0;i < s.size();i++){
if(s[i] == '1'){//等于一时间计数,并且将flag标记为1记录
cnt++;
flag = 1;
}
else{
if(flag){//s[i] == '0'如果这个时间flag被标记说明是前一段1刚结束,将计数的cnt加入数组中
a[n] = cnt*cnt;
af[n] = a[n];
cnt = 0;
if(n % 2 == 0){
a[n] = -a[n];
}
else{
af[n] = -af[n];
}
n++;
flag = 0;
}
}
}
// for(int i = 0;i < n;i++){
// cout << a[i] << " ";
// }
// cout << endl;
cout << max(maxsum(),maxsumf());
}