NOIP模拟赛1(one)

题目描述 Description###

很久以前,有一个序列,序列里填了一些非负整数。
\(zzq\) 每次可以选择序列的一个前缀,把这个前缀里的数都-1,如果这个前缀
中有 0 操作就无法进行。
\(zzq\) 想让序列中最大的数尽量小,请求出这个值。

输入描述 Input Description###

第一行一个整数 \(n\) ,表示序列的长度。
第二行 \(n\) 个整数,表示这个序列。

输出描述 Output Description###

经过若干次操作后序列中最大的数最小能是多少。

样例输入 Sample Input###

3
2 3 3

样例输出 Sample Output###

1

数据范围及提示 Data Size & Hint###

对于 20%的数据,\(n<=5\)\(0<=\) 序列中的每个数\(<=3\)
对于 50%的数据,\(n<=100\)
对于 100%的数据,\(1<=n<=100000\)\(0<=\) 序列中的每个数$<=10^8 $ 。

之前的一些废话###

题解###

二分答案,然后倒着找到第一个比当前二分值大的数,依次减,判断是否小于\(0\) 即可。

代码###

#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<queue>
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;
inline int read()
{
	int x=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){x=x*10+c-'0';c=getchar();}
	return x*f;
}
const int maxn=100010;
int n,A[maxn],L,R=100000000,ans=100000000;
bool judge(int index)
{
	int pos=n;
	while(pos>0 && A[pos]<=index)pos--;
	if(pos==0){ans=min(ans,index);return 1;}
	int MAX=0,tmp;
	for(int i=pos;i>0;i--)
	{
		tmp=A[i]-index;
		MAX=max(MAX,tmp);
		if(A[i]-MAX<0)return 0;
	}
	ans=min(ans,index);
	return 1;
}
int main()
{
	n=read();
	for(int i=1;i<=n;i++)A[i]=read();
	while(R-L>1)
	{
		int mid=(L+R)>>1;
		if(judge(mid))R=mid;
		else L=mid;
	}
	judge(L);judge(R);
	printf("%d\n",ans);
	return 0;
}

总结###

听说有\(O(n)\) 做法。

posted @ 2017-10-31 15:43  小飞淙的云端  阅读(152)  评论(0编辑  收藏  举报