洛谷P1108 低价购买

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int maxn=5005;
 4 int n,len_ans=1,ans;
 5 int a[maxn],d[maxn],len[maxn],f[maxn];
 6 int search(int l,int r,int val)
 7 {
 8     while(l<r)
 9     {
10         int mid=(l+r)>>1;
11         if(d[mid]>val) l=mid+1;
12         else r=mid;
13     }
14     return l;
15 }
16 int main()
17 {
18     scanf("%d",&n);
19     for(int i=1;i<=n;++i) scanf("%d",&a[i]);
20     d[1]=a[1],len[1]=1;//d数组-利用单调性求最长下降子序列 len数组-以i为结尾的下降子序列最大长度 
21     for(int i=2;i<=n;++i)
22     {
23         int pos=search(1,len_ans+1,a[i]);//利用单调性二分求len数组 
24         len[i]=pos;d[pos]=max(d[pos],a[i]);
25         len_ans=max(len_ans,pos);//求最长下降子序列 
26     }
27     //f数组 到达i位置的长度为len[i]的下降子序列(不一定是全局最长下降子序列) 的种类数 
28     for(int i=1;i<=n;++i)
29     {    
30         if(len[i]==1) f[i]=1; 
31         for(int j=1;j<i;++j)//f[i]等于f[j]之和 
32                             //j在i位置以前 len[j]长度为len[i]-1 且 a[j]>a[i]
33         {
34             if(a[j]>a[i]&&len[j]==len[i]-1) f[i]+=f[j];
35             if(a[i]==a[j]&&len[i]==len[j]) f[i]=0;//若i和j的数字相等且下降长度相等就置0 防止重复计算 
36         }
37         if(len[i]==len_ans) ans+=f[i];//若到该点的最大下降长度为全局最长下降长度就把该点方案数计入答案 
38     } 
39     printf("%d %d",len_ans,ans);
40     return 0;
41 }
原文地址:https://www.cnblogs.com/yu-xing/p/10315311.html