1 /*最大递增和最大递减的分析
2 两个其实是一个道理
3 只是维护和边界需要修改一点
4 在理解的过程中突然有个想法:那就是直接套用最大递增,只是把数列改为原来的反数列,然后边界取负无穷大,然后求
5 这个反数列的最大递增数列就可以了,事实证明,这是可行的
6 */
7
8 /*最大递增子序列算法**/
9 #include <iostream>
10 using namespace std;
11 int find(int *a,int len,int n)//修改后的二分查找,若返回值为x,则a[x]>=n
12 {
13 int left=0,right=len,mid=(left+right)/2;
14 while(left<=right)
15 {
16 if(n>a[mid]) left=mid+1;//维护最大
17 else if(n<a[mid]) right=mid-1;
18 else return mid;
19 mid=(left+right)/2;
20 }
21 return left;
22 }
23 int main()
24 {
25 int n,a[100],c[100],i,j,len,b[100];//新开一变量len,用来储存每次循环结束后c中已经求出值的元素的最大下标
26 while(cin>>n)
27 {
28 for(i=0;i<n;i++)
29 cin>>a[i];
30 b[0]=1;
31 c[0]=-1;//边界
32 c[1]=a[0];
33 len=1;//此时只有c[1]求出来,最长递增子序列的长度为1.
34 for(i=1;i<n;i++)
35 {
36 j=find(c,len,a[i]);
37 c[j]=a[i];
38 if(j>len)//要更新len,另外补充一点:由二分查找可知j只可能比len大1
39 len=j;//更新len
40 }
41 cout<<len<<endl;
42 }
43 return 0;
44 }
45
46 /*最大递减子序列算法,都差不多*/
47 #include <iostream>
48 using namespace std;
49 int find(int *a,int len,int n)//修改后的二分查找,若返回值为x,则a[x]>=n
50 {
51 int left=0,right=len,mid=(left+right)/2;
52 while(left<=right)
53 {
54 if(n<a[mid]) left=mid+1;//维护和递增刚好相反
55 else if(n>a[mid]) right=mid-1;
56 else return mid;
57 mid=(left+right)/2;
58 }
59 return left;
60 }
61 int main()
62 {
63 int n,a[100],c[100],i,j,len,b[100];//新开一变量len,用来储存每次循环结束后c中已经求出值的元素的最大下标
64 while(cin>>n)
65 {
66 for(i=0;i<n;i++)
67 cin>>a[i];
68 b[0]=1;
69 c[0]=0x3f3f3f3f;//边界保证递减
70 c[1]=a[0];
71 len=1;//此时只有c[1]求出来,最长递增子序列的长度为1.
72 for(i=1;i<n;i++)
73 {
74 j=find(c,len,a[i]);
75 c[j]=a[i];
76 if(j>len)//要更新len,另外补充一点:由二分查找可知j只可能比len大1
77 len=j;//更新len
78 }
79 cout<<len<<endl;
80 }
81 return 0;
82 }
83 */
84 /*最大递减计数问题*/
85 #include<stdio.h>
86 #include<string.h>
87 #include<iostream>
88 using namespace std;
89 const int maxn=5555;
90 int a[maxn],dp[maxn],f[maxn];
91 int main()
92 {
93 int n,i,j;
94 scanf("%d",&n);
95 for( i=1;i<=n;i++)
96 scanf("%d",&a[i]);
97 for( i=1;i<=n;i++)
98 {
99 dp[i]=1;//每个一i结尾的最下都是1
100 f[i]=1;//初始化为最大方案,有n个
101 }
102 for( i=1;i<=n;i++)
103 for( j=i+1;j<=n;j++)
104 if(a[i]>a[j])
105 {
106 if(dp[j]<dp[i]+1)//继续增加长度
107 {
108 dp[j]=dp[i]+1;
109 f[j]=f[i];//这条路还没走完
110 }
111 else if(dp[j]==dp[i]+1)//说明到这个点有多条路
112 f[j]+=f[i];
113 }
114 else
115 if(a[i]==a[j])//重复了,直接忽略这个点,将到这个点的方案数目置为0
116 f[j]=0;
117 // for(int i=1;i<=n;i++)
118 // printf("%d %d %d\n",i,dp[i],f[i]);
119 int max=0,answer=0;
120 for( i=1;i<=n;i++)
121 if(max<dp[i])
122 max=dp[i];
123 for( i=1;i<=n;i++)
124 if(max==dp[i])
125 answer+=f[i];
126 printf("%d %d\n",max,answer);
127 return 0;
128 }
129
130 /*最大递增计数问题
131 嗯!借用开头的结论,将原来的数列取反,然后求递减数列的方案数目*/
132
133 /*总结:其实最大递增和最大递减就是同一个道理,相互是对方的反面*/