Description

给出一个数列,求出这个序列的最长下降子序列的长度及方案数,子序列中的权值完全相同视为同一个序列

Input

第一行一个整数n,接下来一行n个整数表示序列的权值

Output

一行两个整数分别表示最长的长度及方案数

Sample Input

样例输入1:

12

68 69 54 64 68 64 70 67 78 62 98 87

样例输入2:

3

3 2 2

样例输出1:

4 2

样例输出2:

2 1

HINT

数据范围:

对于20%的数据n <= 10

对于50%的数据n <= 200

对于100%的数据n<= 5000,权值<= 100000,答案不会超出int64(pascal),long long(c++)范围


要求出最长下降子序列长度及方案数是非常容易的. 关键在于去重.

对于去重, 可以从头到尾再DP一次.

第一次DP得到f[i], 即以i为结尾的子串的个数.

第二次DP维护cnt[i], 表示以i为结尾的长度为f[i]的不同子串的个数.

具体维护方法是, j从前往后扫, 至i的位置. 假若有 f[j] == f[i] - 1 且 满足a[j] > a[i], 则将j统计入i的前一位中, 即 cnt[i] += cnt[j]. 对于f[i] == 1的位置, cnt[i]直接赋值为1, 表示有且仅有一种情况, 即为它本身. 至于去重, 假如有 a[j] == a[i] 且 j < i, 则将cnt[j]直接赋值为0, 表示以j为结尾的情况在i中都已经进行累加, 以避免后面重复计算.

这题当时不会写, 只拿了暴力分20, 真的很不应该.

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
const int maxN = (int)5e5;
int a[maxN];
int f[maxN];
long long cnt[maxN];
int main()
{
#ifndef ONLINE_JUDGE
freopen("down.in", "r", stdin);
freopen("down.out", "w", stdout);
#endif
int n;
cin >> n;
for(int i = 0; i < n; i ++)
cin >> a[i];
memset(f, 0, sizeof(f));
for(int i = 0; i < n; i ++)
{
for(int j = 0; j < i; j ++)
if(a[j] > a[i])
f[i] = max(f[j] + 1, f[i]);
if(! f[i])
f[i] = 1;
}
for(int i = 0; i < n; i ++)
{
if(f[i] == 1)
cnt[i] = 1;
for(int j = 0; j < i; j ++)
if(a[j] > a[i] && f[j] == f[i] - 1)
cnt[i] += cnt[j];
for(int j = 0; j < i; j ++)
if(f[j] == f[i] && a[j] == a[i])
cnt[j] = 0;
}
long long maxLen = 0, ans = 0;
for(int i = 0; i < n; i ++)
{
if(f[i] > maxLen)
maxLen = f[i], ans = cnt[i];
else if (f[i] == maxLen)
ans += cnt[i];
}
cout << maxLen << ' ' << ans << endl;
}

随机推荐

  1. LeetCode(201) Bitwise AND of Numbers Range

    题目 Given a range [m, n] where 0 <= m <= n <= 2147483647, return the bitwise AND of all numb ...

  2. LeetCode(123) Best Time to Buy and Sell Stock III

    题目 Say you have an array for which the ith element is the price of a given stock on day i. Design an ...

  3. The 2018 ACM-ICPC Chinese Collegiate Programming Contest Take Your Seat

    /* 证明过程如下 :第一种情况:按1到n的顺序上飞机,1会随意选一个,剩下的上去时若与自己序号相同的座位空就坐下去,若被占了就也会随意选一个.求最后一个人坐在应坐位置的概率 */ #include ...

  4. SQL_3_表达式、条件语句与运算

    加号的两种用法: 1.在SELECT子句中使用+号以执行对数据的运算并将结果显示出来. SELECT ITEM WHOLESALE WHOLESALE+0.15 FROM PRICE; 还可以重命名新 ...

  5. SPOJ FFT TSUM

    第一道FFT的题目. 在网上找了很多FFT的资料,但一直都看不懂,最后是看算法导论学的FFT,算法导论上面写的很详细,每一步推导过程都有严格的证明. 下面说这道题 题意: 给一个序列s,有n个不互相同 ...

  6. C++ 指针的小知识

    看个小例子: char* fun1(){ char * p = (char*)malloc(100); p = "helloww"; return p;} void fun2(ch ...

  7. Hibernate框架简述(转)

    转自:http://www.cnblogs.com/eflylab/archive/2007/01/09/615338.html Hibernate的核心组件在基于MVC设计模式的JAVA WEB应用 ...

  8. 性能测试之七--jdbc

    jdbs用任意协议打开都行,具体脚本见下 在vuser_init里面 #include "Ptt_Mysql.h" vuser_init() { lr_load_dll (&quo ...

  9. 【Luogu】P2569股票交易(单调队列优化DP)

    题目链接 首先这题可以肯定的是朴素DP秒出.然后单调队列优化因为没接触过所以不会emmm 而且脑补没补出来 坐等四月省选倒数第一emmm 心态爆炸,偷懒放题解链接 #include<cstdio ...

  10. VK Cup 2016 - Qualification Round 1——A. Voting for Photos(queue+map)

    A. Voting for Photos time limit per test 1 second memory limit per test 256 megabytes input standard ...