
此题,如果以某同学(t[i])作为最中间的那个人,如果要使此时能留下的人最多,那么我们就要找出其左边最长的增序列和右边的减序列,那么对于t[i],如何在其左边筛选出最长的增序列呢?
用l[i]记录以f[i]为t[i]时,递增的身高个数,首先,如果i=1,那么l[1]必然为1,再看l[2],如果f[2]>f[1],那么此时l[2]=2,否则l[2]=1,所以很容易得出规律,对于一个f[i],如果左边有数字比它小,以这个数字为t[i]时递增个数num,l[i]可以为numm+1,遍历其左边数字,便可以得到最大值。同理右边也是。最后留下来的人数为l[i]+r[i]-1;我们让每个f[i]当一次t[i],找出最后留下来人数最大值即可。
#include<stdio.h>
int f[105],n,l[105],r[105];
int main()
{
int max=0;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
l[i]=1;
r[i]=1;
}
for(int i=1;i<=n;i++)
{
scanf("%d",&f[i]);
}
for(int i=2;i<=n;i++)
{
for(int j=i-1;j>=1;j--)
{
if(f[i]>f[j]&&l[i]<=l[j]) l[i]=l[j]+1;
}
}
for(int i=n-1;i>=1;i--)
{
for(int j=i+1;j<=n;j++)
{
if(f[i]>f[j]&&r[i]<=r[j]) r[i]=r[j]+1;
}
}
for(int i=1;i<=n;i++)
{
//printf("%d %d\n",l[i],r[i]);
if(max<r[i]+l[i]-1) max=r[i]+l[i]-1;
}
printf("%d",n-max);
return 0;
}

用f[i][j]表示用前i种花填满j个花盆的方式,对于第i种花有x朵,如果我们取k朵,那么剩下j-k个花盆,我们还需要用前i-1种花填满这些花盆,所以有f[i-1][j-k]种方式,对于第i种花我们可以取的数量不能超过j和a[i],将所有能取的方式加起来,就是f[i][j];
#include<stdio.h>
int main()
{
int n,m;
int f[105][105]={0},a[106];
scanf("%d %d",&n,&m);
f[0][0]=1;
for(int i=1;i<=n;i++) scanf("%d",&a[i]);
for(int i=1;i<=n;i++)
{
for(int j=0;j<=m;j++)
{
for(int k=0;k<=j&&k<=a[i];k++)
{
f[i][j]+=f[i-1][j-k];
f[i][j]=f[i][j]%1000007;
}
}
}
printf("%d",f[n][m]);
return 0;
}