题目描述
题目描述:
为了迎接奥运,市体育局举行手拉手大包围活动,开始时N个人手拉手围成一个圈。后来这些人中的一些按顺序向里面出圈形成一个新圈。从而使原圈形成一个从高到低,最低与最高连接的圈。新圈重复相同的操作,直到没有人要出圈为止。问最少要形成多少个这样的圈。
输入格式
输入:第一行N个人,第二行输入N个人的身高(每个身高中用空格隔开)N<=1000
输出格式
输出:最少形成多少个这样的圈。
样例输入
样例输出
很容易看出和导弹拦截的第二问是一样的模型。。只是多了环
只是我笔算验证的时候很是不确定,因为样例都画不出来。。然后,猥琐地瞟了一眼讨论,大家都是这样想的,于是乎就打下去了
是那一个定理,下降子序列的个数等于最长不降子序列的长度。
但是由于有环,因此要枚举断点,每次都要把s数组初始化(高度是无限高),s[1]要设成第一个点然后从第二个点开始递推,不然没法递推下去
提交三次:
1、超时,朴素O(n^3)
2、超时,加了几个系数优化,无用。
3、AC,改了二分,因为在同一个大区间内,一个较短的下降序列和一个较长的下降序列,(我们只记录下序列中最高的那个最低的一个序列),前者中最高的必定比后者最高的矮!因此对于可行性有单调性。
应该说现在二分实现上比较熟了吧,只是可能有些建模,要找出单调性,不知道能力如何
#include <cstdio>
#include <string>
#include <cstring>
inline long getint()
{
long rs=0;bool sgn=1;char tmp;
do tmp = getchar();
while (!isdigit(tmp)&&tmp-'-');
if (tmp=='-'){tmp=getchar();sgn=0;}
do rs=(rs<<3)+(rs<<1)+tmp-'0';
while (isdigit(tmp=getchar()));
return sgn?rs:-rs;
}
long h[1010];
long s[1010];
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
long maxs = 0;
long height = 0;
long find()
{
long l = 0;
long r = maxs;
long out = 0;
while (l <= r)
{
long mid = (l+r)>>1;
if (h[s[mid]]<=height)
{
if (out < mid)
out = mid;
l = mid+1;
}
else
{
r = mid-1;
}
}
return out;
}
int main()
{
freopen("olympic.in","r",stdin);
freopen("olympic2.out","w",stdout);
long n = getint();
for (long i=1;i<n+1;i++)
{
h[i] = getint();
h[i+n] = h[i];
}
long ans = 0x7f7f7f7f;
h[1005] = 0x7f7f7f7f;
for (long k=1;k<n;k++)
{
for (long i=1;i<1005;i++)
s[i] = 1005;
maxs = 0;
s[1] = k;
maxs = 1;
for (long i=k+1;i<k+n;i++)
{
height = h[i];
long re = find();
if (h[s[re+1]] > h[i])
s[re+1] = i;
maxs = MAX(maxs,re+1);
}
ans = MIN(ans,maxs);
}
printf("%ld",ans);
return 0;
}
朴素:
#include <cstdio>
#include <string>
#include <cstring>
inline long getint()
{
long rs=0;bool sgn=1;char tmp;
do tmp = getchar();
while (!isdigit(tmp)&&tmp-'-');
if (tmp=='-'){tmp=getchar();sgn=0;}
do rs=(rs<<3)+(rs<<1)+tmp-'0';
while (isdigit(tmp=getchar()));
return sgn?rs:-rs;
}
long h[1010];
long f[1010];
#define MAX(a,b) ((a)>(b)?(a):(b))
#define MIN(a,b) ((a)<(b)?(a):(b))
int main()
{
freopen("olympic.in","r",stdin);
freopen("olympic.out","w",stdout);
long n = getint();
for (long i=1;i<n+1;i++)
{
h[i] = getint();
h[i+n] = h[i];
}
long ans = 0x7f7f7f7f;
for (long k=1;k<n;k++)
{
long _ans = 0;
for (long i=k;i<k+n;i++)
{
f[i] = 1;
}
for (long i=k;i<k+n;i++)
{
for (long j=k;j<i;j++)
{
if (h[i] >= h[j])
{
f[i] = MAX(f[i],f[j]+1);
_ans = MAX(_ans,f[i]);
if (_ans >= ans)
{
i = k+n+1;
break;
}
}
}
}
ans = MIN(ans,_ans);
}
printf("%ld",ans);
return 0;
}