第一问,求最长下降子序列长度。
设a表示数据,len(i)=前i个数中最长下降子序列长度,状态转移方程 len (i)=max{len(j)+1}(j<i,a[j]>a[i]), 初始化f[i]=1 (i=0...n-1);
第二问:
对于c[i]=前i个数中最长下降子序列的个数,状态转移方程 c[i]=sigma(c[j]) (j<i,a[j]>a[i], len[i]==len[j]+1)
对于重复情况, 每一个可能重复的下降的子序列,它一定是a , b, b (a>b)的情况,开一个数组visited记录b是否出现过,若出现了,就不再计算。
状态转移方程: c[i]=sigma(c[j]) (j<i,a[j]>a[i], len[i]==len[j]+1),visited[j]=false)。
最后是高精度加法,我的版本是每一位存一个数,有待改进。
PS:这次代码风格有点变化。

/**//*
ID: lorelei3
TASK: buylow
LANG: C++
*/

#include <fstream>
#include <memory.h>

using namespace std;

const int MAXN = 5000;
const int MAXP = 50;


class HPNum
{
public:
int length;
int num[MAXP];


HPNum()
{
length=1;
memset(num,0,sizeof(num));
}


void plus(HPNum &p)
{
int len = length>p.length ? length : p.length;

for(int i=0; i<len; ++i)
{
num[i] = num[i]+p.num[i];

if(num[i]>=10)
{
num[i]-=10;
num[i+1]++;
}

}
if(num[len]>0)
len++;
length=len;
}
};

int n;
long maxlen;
long a[MAXN], len[MAXN];
bool visited[20000];
HPNum c[MAXN];

ifstream fin("buylow.in");
ofstream fout("buylow.out");


void input()
{
fin>>n;

for(int i=0; i<n; ++i)
{
fin>>a[i];
len[i]=1;
}
}


void dp()
{
int i,j;
maxlen=1;
for(i=1; i<n; ++i)

for(j=i-1; j>=0; --j)
{
if(a[i]<a[j] && len[i]<len[j]+1)
len[i] = len[j]+1;
if(maxlen<len[i])
maxlen = len[i];
}
for(i=0; i<n; ++i)

if(len[i]==1)
{
c[i].length=1;
c[i].num[0]=1;

}else
{
memset(visited, false, sizeof(visited));

for(j=i-1; j>=0; --j)
{

if(len[i]==len[j]+1 && !visited[a[j]] && a[i]<a[j])
{
c[i].plus(c[j]);
visited[a[j]]=true;
}
}
}
}


void output()
{
int i;
HPNum sum;
sum.length=1;
sum.num[0]=0;
memset(visited, false, sizeof(visited));
for(i=n-1; i>=0; --i)

if(len[i]==maxlen && !visited[a[i]])
{
sum.plus(c[i]);
visited[a[i]]=true;
}

fout<<maxlen<<" ";

for(i=sum.length-1; i>=0; --i)
fout<<sum.num[i];

fout<<endl;
}


int main()
{

input();

dp();

output();
return 0;
}

posted on 2011-01-27 00:59
小阮 阅读(454)
评论(0) 编辑 收藏 引用 所属分类:
USACO