analysis
Time Limits: 1000 ms Memory Limits: 128000 KB
Description
给你N个数字,将其分成若干子序列,每个序列都必须是递增或递减的.
希望子序列的数量越少越好。
Input
本题有多组数据
对于每组数据,第一行一个整数N
第二行N个整数Ai.
Output
对于每组数据,输出最少的个数
Sample Input
1
5
3
1 3 2
Sample Output
1
2
Hint
数据范围
N<=50
保证Ai中的数字不重复,且0<=Ai<=200
每个输入文件中不超过10组数据
提示
对于Pascal选手,推荐使用seekeof判断文件结束
》》题目感知:题目太码农,解法太玄学!!
总而言之,题目出得有点过于坑
解题思路
主要算法就是搜索,直接暴力,枚举(或二分)答案,然后再深搜迭代加深。
设tot1表示为降序列的个数,tot2表示为升序列的个数,Ui表示为第i个生序列的队首,Di表示为第i个降序列的队首。
有如下几种操作:
- 若tot2=0,新开一个U存入当前的数,深搜一遍;
- 若tot1=0,新开一个D存入当前的数,深搜一遍;
- 若tot1>0且存在Di>当前的数,让当前的数存入符合条件的Di中最小的序列,深搜一遍;
- 若tot2>0且存在Ui<当前的数,让当前的数存入符合条件的Ui中最大的序列,深搜一遍;
- 若tot1>0但不存在Di>当前的数,新开一个D存入当前的数,深搜一遍;
- 若tot2>0但不存在Ui<当前的数,新开一个U存入当前的数,深搜一遍。
注意,一定要按照这种顺序(除非你打得十分优美),否则会TLE,至于为什么,我也不知道。同时,注意一下输入,非常坑。这就是我为什么说“》》题目感知:题目太码农,解法太玄学!!”的原因了。
Codes:
#include<cstdio>
#include<cstring>
#include<cmath>
#define fo(i,x,y) for(int i=x;i<=y;i++)
using namespace std;
int n,a[51],mid,tot1,tot2,U[51],D[51];
char num;
bool q;
void can(int);
int main()
{
for(;;)//相当于while(1)
{
num=getchar();
if(num<'0' || num>'9')break;
int x=num-'0';
for(;;)
{
num=getchar();
if(num<'0' || num>'9')break;
x+=x*9+(num-'0');
}
fo(i,1,x)scanf("%d",&a[i]);
scanf("\n");
n=x;
int l=1,r=floor(sqrt(n)),ans=r;/*枚举到√n即可,易证*/
while(l<=r) //二分
{
mid=(l+r)>>1;
q=0;
tot1=tot2=0;
can(1);
if(q)
{
r=mid-1;
ans=mid;
}else{
l=mid+1;
}
}
printf("%d\n",ans);
}
}
void can(int w)/*搜索顺序很关键*/
{
bool p=0,o=0;
int wz,s,z;
if(tot1+tot2>mid)return;
if(w>n){q=1;return;}
if(tot2==0)
{
U[++tot2]=a[w];
can(w+1);if(q)return;
tot2--;/*这里一定不要丢掉*/
}
if(tot1==0)
{
D[++tot1]=a[w];
can(w+1);if(q)return;
tot1--;/*这里一定不要丢掉*/
}
if(tot1>0)
{
z=0x7fffffff;
for(int i=1;i<=tot1;i++)
{
if(D[i]>a[w] && D[i]<z)
{
z=D[i];wz=i;
}
}
if(z<0x7fffffff)
{
s=D[wz];
D[wz]=a[w];
can(w+1);if(q)return;
D[wz]=s;/*这里一定不要丢掉*/
}else p=1;
}
if(tot2>0)
{
z=-1;
for(int i=1;i<=tot2;i++)
{
if(a[w]>U[i] && U[i]>z)
{
z=U[i];wz=i;
}
}
if(z>-1)
{
s=U[wz];
U[wz]=a[w];
can(w+1);if(q)return;
U[wz]=s;/*这里一定不要丢掉*/
}else o=1;
}
if(p)
{
D[++tot1]=a[w];
can(w+1);if(q)return;
tot1--; /*这里一定不要丢掉*/
}
if(o)
{
U[++tot2]=a[w];
can(w+1);if(q)return;
tot2--;/*这里一定不要丢掉*/
}
}
这些“/这里一定不要丢掉/”,重要的事说三遍,这里说六遍,脑补一下