USACO Buy Low

来源:互联网 发布:法院淘宝司法拍卖网站 编辑:程序博客网 时间:2024/06/07 15:36

移步到新Blog 获得更好的代码阅读体验





这貌似是一道求最长下降序列的线性DP。

首先最长下降序列的状态转移方程是最简单的了QAQ

for (int i=2;i<=day;i++){maxsub=0;for (int j=1;j<=i-1;j++) if (p[j]>p[i]) maxsub=max(maxsub,f[j]);f[i]=maxsub+1;}

当然了f默认值是1;

或者可以这样

for (int i=2;i<=day;i++){    for (int j=i-1;j>=1;j--) if (price[j]>price[i])        f[i]=max(f[j]+1,f[i]);}

接下来是统计方案 如果不计重的话貌似很好办,但要是计重的话,就应该倒推,如果前面的元素k和目前的元素i相等,那么f[k]==f[i],{这是因为统计了最长下降序列(如果是不上升序列的话还要稍微改动一下i对答案的贡献)}

所以k对答案的贡献应是和i相等的,这时可以把i对答案的贡献去掉了,因为以i结尾的组合把i换为k都成立这是由于由k结尾的最长下降序列的方案数只取决于k前面的几个元素(不同元素的组合)而与k无关


从而得出整个状态转移方程:


for (int i=2;i<=day;i++){maxsub=0; equ=0;for (int j=1;j<=i-1;j++) if (p[j]>p[i]) maxsub=max(maxsub,f[j]);f[i]=maxsub+1;for (int j=i-1;j>=0;j--){if (f[j]+1==f[i] && p[j]>p[i]) equ+=n[j];else if (f[j]==f[i] && p[j]==p[i]){n[i]=0;break;}}if (equ!=0) n[i]=equ;}
注意这里n初始化为1,组合数必定大于等于1

所以,完成了全部程序:

#include<cstdio>#include<iostream>#include<cstring>#include<string>#include<cmath>using namespace std;int day,maxsub,equ,tot,p[10010]={0},f[10010]={0},n[10010]={0};int main(){scanf("%d",&day);for (int i=1;i<=day;i++){scanf("%d",&p[i]);f[i]=n[i]=1;}for (int i=2;i<=day;i++){maxsub=0; equ=0;for (int j=1;j<=i-1;j++) if (p[j]>p[i]) maxsub=max(maxsub,f[j]);f[i]=maxsub+1;for (int j=i-1;j>=0;j--){if (f[j]+1==f[i] && p[j]>p[i]) equ+=n[j];else if (f[j]==f[i] && p[j]==p[i]){n[i]=0;break;}}if (equ!=0) n[i]=equ;}maxsub=1; equ=0;for (int i=2;i<=day;i++) if (f[maxsub]<f[i]) maxsub=i;maxsub=f[maxsub];for (int i=1;i<=day;i++) if (maxsub==f[i]) equ+=n[i];//统计所有长度最长的子序列对答案的贡献printf("%d %d\n",maxsub,equ);return 0;}



原创粉丝点击