第一问,求最长下降子序列长度。
设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
小阮 阅读(444)
评论(0) 编辑 收藏 引用 所属分类:
USACO