题意: 有一个长度为N的序列p,该序列保证存在1~N每个值都存在,现在给出一个序列q,长度为N-1,表示序列p相邻两数之差,根据序列q输出序列p
题解: 一开始想复杂了,以为要找什么最大差值最小差值来扩展,又或者枚举的话可能因为不断尝试的过程需要递归搜索,复杂度会很大。。。。
边界条件永远是 1 ~ N
一开始用for循环枚举判断每个值,这个复杂度可能是O(N*N)的,最复杂情况,当2e5个差值是等差序列,差值为1,但是最后一个值的差值存在巨大异常,那么枚举的范围将是2e5,而得到不合法序列的时间将是计算到最后才知道。【第41组case】
考虑两个优化,首先我们知道,在差值确定的情况下,当我们重复计算出某个值的时候,无论枚举任何数,都会出现重复值,因为题意是必须出现1~N所有值,因此不可能出现重复值,一旦出现重复值,就不继续构造该序列,直接无解。
第二个也是最重点的优化,即for枚举改成二分枚举,因为可以知道,当计算一个值出现不合法情况是,如计算出来的值是大于N的或小于0的,可以根据结果调整枚举值的范围,想象该序列是一段折线,那么当某个值大于N时,我们将枚举的第一个值向下调整,当小于0时,第一个值向上调整,那么整个序列都将上移,二分枚举不断找到一个令所有值都合法的序列
最后复杂度,O(N*logN)
代码如下:
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int maxn=2e5+7;
int n,q[maxn];
bool vis[maxn<<1];
vector<int>p;
int main()
{
scanf("%d",&n);
bool flag=false,gg=false;
for(int i=1; i<n; i++)scanf("%d",&q[i]);
int l=1,r=n;
while(l<=r)
{
int i=(l+r)