CSUSTOJ-石上优想要逃离(STL+思维暴力)

题目连接:http://acm.csust.edu.cn/problem/4053
CSDN食用链接:https://blog.csdn.net/qq_43906000/article/details/109520067

Description

由于临近期末考试,辉夜为了不让自己的后辈不及格,对他进行了魔鬼的教导,石上必须每天要完成辉夜指定的题才能回家,不出意外,今天辉夜又出了一道难题,题目如下。

桌子上有 \(n\) 个果实,排成一排,每个果实有一个美味度,每次选择一段连续区间的果实食用,如果这个区间果实的美味度之和\(S_i\)等于上一次食用的区间美味度之和\(S_{i-1}\) ,那么总的美味度就会加上\(|S_i|\);如果不相同, 美味度会变成负无穷,所以你需要避免存在相邻两次选的和不同的情况。\(|S_i|\) 表示 \(S_i\) 的绝对值, 并且当一个区间的果实食用完后,两边剩余的果实并不会合并成连续相邻的果实。初始的美味度为 \(0\) ,请你计算出可以获得的最大的美味度。

特别的,第一次选择任意连续区间的果实食用时,总的美味度始终会加上\(|S_1|\)。即:无论\(S_1\)的值为多少,总有\(S_0 = S_1\)

石上实在写不出这么难的题目,请你帮他计算出正确答案。

input

第一行两个整数\(n(1 \leq n \leq 1e3)\),表示果实的个数

第二行\(n\)个整数,第\(i\)个数\(a_i(-1e5 \leq a_i \leq 1e5)\),表示第\(i\)个果实的美味度

output

一个整数,表示可以获得的最大的美味度

Sample Input 1
7
4 1 2 2 1 5 3
Sample Output 1
18

emmm,这题有点难说实话,对于这个序列而言,如果其序列中的所有数的符号都是一样的那么我们可以直接全部加起来取个绝对值就是最大值了。但难点在于有正数还有负数的情况,通过题目可知,在这种情况下他一定会得到一个\(k\times |S_i|\)的答案,那么我们的目的就是找到这个\(S_i\)并找到这个序列最多可得到多少个\(S_i\),最后我们取个绝对值加起来即可。

现在对于这个\(S_i\)我们可以全部找出来,我们直接枚举一个端点然后枚举另一个端点就可以通过前缀和操作在\(O(n^2)\)的时间内求出全部的\(S_i\),那么看这个时间复杂度应该就是正确的了,但我们现在还需要确定\(k\)的值,很显然,我们不能再跑一次循环,我们只能在\(O(n^2)\)的写法的同时求出\(k\)这个值,那么我们可以联想的就是对每个值做一个映射,然后从最早的区间开始进行无重复区间的累加。那么这个映射只能用map来完成,那么怎么统计区间并判断是否有重叠呢?

首先我们要思考怎么枚举区间呢?你要么枚举起点要么枚举终点,但很明显,枚举起点的话很难处理重叠部分,但如果我们枚举终点再枚举起点的话对于重叠部分就很好处理,我们保存每个值的最后区间的终点\(ed_i\),对于每个起点大于\(ed_i\)的区间我们不做统计就好了。也就是说我们对于每个值需要保存它的数量和其最后区间的终点,那么我们可以用map套个结构体或者套个pair

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

const int mac=1e3+10;
typedef long long ll;
const int inf=1e9+10;
typedef pair<int,int> pill;

int a[mac];
int ans=0,sum[mac];
map<int,pair<int,int> >mp;

int main(int argc, char const *argv[])
{
	int n,flag=0;
	scanf ("%d",&n);
	for (int i=1; i<=n; i++){
		scanf ("%d",&a[i]);
		sum[i]=sum[i-1]+a[i];
	}
	for (int i=1; i<=n; i++){
		for (int j=i-1; j>=0; j--){
			int val=sum[i]-sum[j];
			if (!mp[val].first) mp[val]={1,i};
			else {
				if (mp[val].second<j+1) 
					mp[val].first++,mp[val].second=i;
			}
			ans=max(ans,abs(val)*mp[val].first);
		}
	}
	printf ("%d\n",ans);
	return 0;
}

当然,上面的代码是有了很多程度简化的,实际上刚开始的时候用的是map套vector套pair来维护这个东西的,但更容易理解。
以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

const int mac=1e3+10;
typedef long long ll;
const int inf=1e9+10;
typedef pair<int,int> pill;

int a[mac];
int ans=0,sum[mac];
map<int,vector<pill> >mp;

int main(int argc, char const *argv[])
{
	int n,flag=0;
	scanf ("%d",&n);
	for (int i=1; i<=n; i++){
		scanf ("%d",&a[i]);
		sum[i]=sum[i-1]+a[i];
	}
	for (int i=1; i<=n; i++){
		for (int j=i-1; j>=0; j--){
			int val=sum[i]-sum[j];
			if (mp[val].empty()){
				mp[val].push_back({j+1,i});
			}
			else {
				int p=mp[val][mp[val].size()-1].second;
				if (p<j+1) mp[val].push_back({j+1,i}); 	
			}
			ans=max(ans,abs(val)*(int)mp[val].size());
		}
	}
	printf ("%d\n",ans);
	return 0;
}
posted @ 2020-11-07 18:34  lonely_wind  阅读(140)  评论(0编辑  收藏  举报