求最长下降子序列,平方的算法就可以过
第二问要求这些子序列的个数,相同的序列不可重复算,也是类似第一个问题的动态规划解法,但要处理重复。
这里注意到一个性质,如果对于两个相同的数,如A[i]和A[j](i<j,),如果以他们结尾的最长下降序列大小相同, 那么在i和j之间一定不存在异于A[i]的数A[k](i<k<j),使得以A[k]结尾的最长下降序列和以A[i]结尾的最长下降序列相同。由反证法很容易证明。
由此,我们可以得到一个算法,每次只处理相同数最右边的一个,具体参考实现的22~30行。另外,此题要用高精度,万恶题。。。
- int main()
- {
- int i, j, k;
- freopen("buylow.in", "r", stdin);
- freopen("buylow.out", "w", stdout);
- scanf("%d",&n);
- for(i = 1; i <= n; i++) scanf("%d",&a[i]);
- a[0] = INT_MAX;
- int best = 1; d[1] = 1;
- for(i = 2; i <= n; i++){
- d[i] = 1;
- for(j = 1; j < i; j++)
- if(a[j] > a[i]) d[i] = max(d[i], d[j] + 1);
- best = max(best, d[i]);
- }
- cnt[1] = 1;
- for(i = 2; i <= n; i++){
- int last = -1;
- if(d[i] == 1) { cnt[i] = 1; continue;}
- for(j = i - 1; j >= 1; j--)
- {
- if(d[j] == d[i]-1 && a[j] > a[i] && a[j] != last){
- cnt[i] += cnt[j];
- last = a[j];
- }
- }
- }
- BigInt ret = 0;
- int last = -1;
- for(i = n; i >= 1; i--)
- {
- if(d[i] == best && a[i] != last)
- {
- ret += cnt[i];
- last = a[i];
- }
- }
- cout << best << " " << ret << endl;
- scanf("%d",&n);
- }