补充一下:
大佬第一种做法,两种优化,其实还可以优化。
第二个优化(先说第二个 ):缩小第一个元素的范围。我这里假设第一个元素是start,那么 max(-maxnum+1,1)<=start<=min(n,n-maxnum),其中maxnum,minnum是差值的前缀和的最大值和最小值。为啥?自己悟吧。然后就是用二分在这个范围里找。
第一个优化:不能有重复的。我这里是这样处理的。把差值的前缀和数组s[i]求出来,那么我们要求的数组就是start+s[i] ,那么如果我们要求的数组里有重复的元素,则s[i]有等于0的 或者 s[i] 有相等的。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<iostream>
#include<map>
#include<climits>
#define ll long long
using namespace std;
ll n;
ll s[2*100000+100];
int a[2*100000+100];
int flag[2*100000+100];
int ans[2*100000+100];
ll r,l,mid;
int check(ll mid) //枚举start
{
for(int i=1;i<n;i++)
{
ans[i]=s[i]+mid;
if(ans[i]<0)
return 1;
if(ans[i]>n)
return 0;
}
return 2;
}
int main()
{
scanf("%lld",&n);
memset(s,0,sizeof(s));
ll maxnum=-INT_MAX,minnum=INT_MAX;
for(int i=1;i<n;i++)
{
scanf("%d",&a[i]);
s[i]=s[i-1]+a[i];
flag[i]=s[i];
maxnum=max(maxnum,s[i]);
minnum=min(minnum,s[i]);
}
/*去重------------------------------------------------------------------------*/
/*
for(int i=1;i<n;i++)
cout<<s[i]<<" ";
cout<<endl;
*/
sort(flag+1,flag+n);
/*
for(int i=1;i<n;i++)
cout<<flag[i]<< " ";
cout<<endl;
*/
int m=unique(flag+1,flag+n)-flag-1; //cout<<m<<endl;
if(m!=n-1)
{
cout<<-1<<endl;
return 0;
}
int *x=find(flag+1,flag+1+m,0);
//cout<<*x<<endl;
if(x!=flag+1+m) //找到了
{
cout<<-1<<endl;
return 0;
}
/*-------------------------------------------------------------------------------------*/
/*二分找第一个数*/
ll start;
start=max(-minnum+1,(ll)1);
if(start>n-maxnum)
{
cout<<-1<<endl;
return 0;
}
l=start;r=min(n-maxnum,n);
int ok=0;
while(l<=r)
{
mid=(l+r)>>1;
if(check(mid)==1)
l=mid+1;
else if(check(mid)==0)
r=mid-1;
else
{
ok=1;
break;
}
}
if(ok==0)
cout<<-1<<endl;
else
{
cout<<start<<" ";
for(int i=1;i<n;i++)
printf("%d ",ans[i]);
cout<<endl;
}
return 0;
}