P1667 数列(思维好题)

题目链接

题目描述

给定一个长度是n的数列A,我们称一个数列是完美的,当且仅当对于其任意连续子序列的和都是正的。现在你有一个操作可以改变数列,选择一个区间[X,Y]满足Ax +Ax+1 +…+ AY<0,1 输入输出格式
输入格式:
第一行一个数n,以下n个数。
【数据规模】对于100%的数据,满足1≤N≤10^5; 1≤|A[i]|≤2^31-1。
输出格式:一个数表示最少的操作次数,如果无解输出-1。


一眼看上去,像前缀和,于是手动试了好几组数据后,得出神奇结论:
每次对[l,r]操作,其实是交换sum[l-1]与sum[r](sum为前缀和)
然后再对结果分析得出此题即为通过交换操作把一个无序的前缀和序列变为有序(当有负数或前缀和相等的,即为无解情况)

#include
#include
#include
#include
using namespace std;
int n,a[100005];
int sum[100005],sump[100005];
int id[100005];
bool cmp(int x,int y)
{
	return sum[x]<sum[y];
}
int main()
{
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		cin>>a[i];
		id[i]=i;
	}
	for(int i=1;i<=n;i++)
	{
		sum[i]=sum[i-1]+a[i];
		sump[i]=sum[i];
	}
	sort(sump,sump+n+1);
	if(sump[1]<0) { cout<<"-1"<<endl; return 0; }
	for(int i=1;i<n;i++) if(sump[1]<0) { cout<<"-1"<<endl; return 0; }
	sort(id+1,id+n+1,cmp);
	for(int i=1;i<=n;i++) sum[id[i]]=i;//小小的离散化
	int ans=n;
	for(int i=1;i<=n;i++)
	{
		if(sum[i]==i) ans--;
		else { swap(id[sum[i]],id[i]); swap(sum[id[sum[i]]],sum[i]);}
	}
	cout<<ans<<endl;
} 

你可能感兴趣的:(心路历程)