您的位置:首页 > 其它

POJ 1952 Buy Low,Buy Lower

2016-07-13 20:03 337 查看
题目大意:

求最长下降子序列及其个数(严格的…..)

分析:

求最长上升子序列很简单大家都会,那么方案数呢??记得之前做过一道题求的是最短路的计数,那道题是在更新最短路径时更新其对应方案数,这道题是不是也可以这样做呢?所以我们定义num[i]代表前i个数中最长子序列的个数,如果f[i]=f[j]+1(i>j)就代表i可以由j转移而来,所以j的方案数目包含在i中,那么num[i]=num[i]+num[j]。有了怎么转移,我们还要考虑一个严肃的问题,怎么去重??

看下面一段代码:

for(int i=2;i<=n;i++)
for(int j=i-1;j>=1;j--){
if(f[i]==f[j]+1&&a[j]>a[i])
num[i]+=num[j];
if(a[i]==a[j]){
if(f[i]==1)
num[i]=0;
break;
}
}


这是什么意思呢??O(≧口≦)O

我们还是规定i>j,如果a[i]=a[j](因为我们是倒着往前找的)就代表我们不需要再往前枚举更新方案数目了,因为j之前的方案数目已经包含在j中了,而如果f[i]=1这代表什么呢??代表i前面没有比它大的数,那么显然f[j]也应该等于1,就是说ij方案数完全相同,这么来说如果我们保留i的方案数目,那么就会和j重复,而又因为i在j的后面所以我们显然是要保留j而把i的方案数目清零

代码如下:

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
using namespace std;
const int maxn=5000+5;
int n,a[maxn],f[maxn],num[maxn];
inline int read(){
char ch=getchar();
int f=1,x=0;
while(!(ch>='0'&&ch<='9')){
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
x=x*10+ch-'0',ch=getchar();
return f*x;
}
signed main(void){
n=read();
for(int i=1;i<=n;i++)
a[i]=read(),f[i]=1,num[i]=0;
for(int i=1;i<=n;i++)
for(int j=1;j<i;j++)
if(a[i]<a[j])
f[i]=max(f[i],f[j]+1);
for(int i=1;i<=n;i++)
if(f[i]==1)
num[i]=1;
for(int i=2;i<=n;i++) for(int j=i-1;j>=1;j--){ if(f[i]==f[j]+1&&a[j]>a[i]) num[i]+=num[j]; if(a[i]==a[j]){ if(f[i]==1) num[i]=0; break; } }
int mx=0,ans=0;
for(int i=1;i<=n;i++)
mx=max(mx,f[i]);
for(int i=1;i<=n;i++)
if(f[i]==mx)
ans+=num[i];
cout<<mx<<" "<<ans<<endl;
return 0;
}


by >o< neighthorn
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: