最长不下降子序列 输出方案数

对于最长不下降子序列的求解,朴素的解法是N^2的,也可以用单调队列优化,从而降时间复杂度为Nlog(n).

涉及到方案数的输出时,只需要降长度为1的最长XX子序列的方案数赋成1,其他的长度的方案数均由前一个长度的方案推出.

如下图所示:

首先用朴素的最长非降子序列的方法求出每一个在最优序列中的位置:

建立如下的表

值的大小:                 68     69     54     64     68     64     70     67     78     62     98     87

在序列中的位置           3         4      1       2       3       2       3      2        2      2       1       1(这里的在序列中的位置即是指以这个数为起点的最长XX子序列的长度)

下面是对方案的判重,这列我们借助一个一维的辅助数组来帮助判重.

time[n+1].z[0]=1;
    time[n+1].z[1]=1;   
    for (int i=n;i>0;i--)
    {
       panchong[0]=0;//用来帮助判重的辅助数组.
       for (int j=i+1;j<=n+1;j++)
       {
         bool boo=false;  
         if (f[j]==f[i]-1&&a[j]<a[i])
         {
           for (int k=1;k<=panchong[0];k++)
             if (panchong[k]==a[j]) {boo=true;break;}
           if (boo==false){panchong[++panchong[0]]=a[j];add(time[i].z,time[j].z,time[i].z);}
         }
       }
    }

下面给出输出方案数的程序:

题目是USACO的

Section 4.3 .1Buy Low, Buy Lower

(代码比较冗余,可去NOCOW上看较为标准的代码)

#include <cstdlib>
#include <cstdio>
#include <cstring>
struct
{
      int z[15];
}time[10000];
int panchong[10000];
int a[10000];
int f[10000];
void add(int a[15],int b[15],int c[15])
{
     int d[15];
     memset(d,0,sizeof(d));
     int len;
     if (a[0]>b[0]) len=a[0];else len=b[0];
     for (int i=1;i<=len;i++)
     {
         d[i]+=(a[i]+b[i]);
         d[i+1]+=(d[i]/100000000);
         d[i]=d[i]%100000000;
     }
     d[0]=len+2;
     while (d[d[0]]==0&&d[0]>0) d[0]--;
     while (d[d[0]]>=100000000) { d[d[0]+1]=d[d[0]]/100000000; d[0]++;}
     memset(c,0,sizeof(c));
     for (int i=0;i<=d[0];i++)
       c[i]=d[i];
}
void print(int a[15])
{
     printf("%d",a[a[0]]);
     for (int i=a[0]-1;i>0;i--)
     {
         if (a[i]/10000000==0) printf("0");
         if (a[i]/1000000==0) printf("0");
         if (a[i]/100000==0) printf("0");
         if (a[i]/10000==0) printf("0");
         if (a[i]/1000==0) printf("0");
         if (a[i]/100==0) printf("0");
         if (a[i]/10==0) printf("0");
         printf("%d",a[i]);
     }
     printf("\n");
}
int main()
{
    freopen("plane.in","r",stdin);
    freopen("plane.out","w",stdout);
    int n;
    scanf("%d",&n);
    for (int i=1;i<=n;i++)
      scanf("%d",&a[i]);
    a[n+1]=-1000000;
    f[n+1]=0;  
    for (int i=n;i>0;i--)
      for (int j=i+1;j<=n+1;j++)
      {
          if (a[i]>a[j]&&f[i]<f[j]+1) f[i]=f[j]+1;
      } 
    memset(time,0,sizeof(time));  
    time[n+1].z[0]=1;
    time[n+1].z[1]=1;   
    for (int i=n;i>0;i--)
    {
       panchong[0]=0;
       for (int j=i+1;j<=n+1;j++)
       {
         bool boo=false;  
         if (f[j]==f[i]-1&&a[j]<a[i])
         {
           for (int k=1;k<=panchong[0];k++)
             if (panchong[k]==a[j]) {boo=true;break;}
           if (boo==false){panchong[++panchong[0]]=a[j];add(time[i].z,time[j].z,time[i].z);}
         }
       }
    }
    int maxx=0;
    for (int i=1;i<=n;i++)
      if (f[i]>maxx) {maxx=f[i];};
    panchong[0]=0;  
    int biao[15];
    memset(biao,0,sizeof(biao));
    for (int i=1;i<=n;i++)
      if (f[i]==maxx)
      {
        bool boo=false;             
        for (int k=1;k<=panchong[0];k++)
                 if (a[i]==panchong[k])  {boo=true;break;} 
        if (boo==false) {panchong[++panchong[0]]=a[i];add(biao,time[i].z,biao);}
      }         
    printf("%d ",maxx);
    print(biao);
    return 0;
}  

 

 

foreverzsz原创,转载请注明出处。

本文出处:http://www.cnblogs.com/foreverzsz/archive/2010/11/12/1875662.html

转载于:https://www.cnblogs.com/foreverzsz/archive/2010/11/12/1875662.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值