Luckyleaves's Blog

stay hungry,stay foolish greedy and lucky

P1108 低价购买

题目传送门

$Noip2021$ 被 $Dp$ 打爆了,回来开始刷 $Dp$ 的题(一道不会),自闭了…….

Solution

怎么说呢?刚刚看题的时候,就觉得这道题其实就是最长下降子序列的裸题(看到5000的数据,甚至还以为有点水),兴冲冲的开了,写完才发现还要求方案数,仔细想了想,才发现自己只会 $O(n)$ 记录,$O(n ^ 2)$ 枚举, 时间复杂度 $O(n ^ 3)$ ,被打爆了 $QWQ$。

仔细想想(一上午没了),其实这题还是可做,我们设 $f_i$ 为以第 $i$ 项结尾的最长下降子序列的长度,然后 $t_i$ 为构成这类序列(以第 $i$ 项结尾,长度为 $f_i$)的方案数,我们不难发现,如果第 $i$ 项和第 $j$ 项的值相同,那么对于能够接在 $j$ 前面的数,一定能够接在 $i$ 前面,那么我们只需将 $t_j$ 清空,就完成了去重(作者太懒,不想画图)。

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 5005;
int n, k;
int root;
LL f[N];
LL a[N];
LL ans, cnt;
int t[N];
int main()
{
scanf("%d", &n);
for(int i = 1;i <= n;i ++)
scanf("%lld", &a[i]);
for(int i = 1;i <= n;i ++)
{
for(int j = 1;j < i;j ++)
if(a[i] < a[j]) f[i] = max(f[i], f[j] + 1);
if(f[i] == 0) f[i] = 1;
if(ans < f[i]) ans = f[i];
for(int j = 1;j < i;j ++)
{
if(f[i] == f[j] && a[i] == a[j]) t[j] = 0;
if(f[i] == f[j] + 1 && a[i] < a[j]) t[i] += t[j];
}
if(!t[i]) t[i] = 1;
}
for(int i = 1;i <= n;i ++)
if(f[i] == ans) cnt += t[i];
cout << ans << " " << cnt;
return 0;
}

双倍经验

题目传送门, 题目一摸一样,只不过卡了高精,但貌似 $double$ 可以卡过去?

代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
#include<bits/stdc++.h>
#define LL long long
using namespace std;
const int N = 5005;
int n, k;
int root;
LL f[N];
LL a[N];
LL ans;
long double cnt;
template <class T>
void write(T x)
{
if(x > 9) write(x / 10);
putchar((x % 10) + '0');
}
double t[N];
int main()
{
scanf("%d", &n);
for(int i = 1;i <= n;i ++)
scanf("%lld", &a[i]);
for(int i = 1;i <= n;i ++)
{
for(int j = 1;j < i;j ++)
if(a[i] < a[j]) f[i] = max(f[i], f[j] + 1);
if(f[i] == 0) f[i] = 1;
if(ans < f[i]) ans = f[i];
for(int j = 1;j < i;j ++)
{
if(f[i] == f[j] && a[i] == a[j]) t[j] = 0;
if(f[i] == f[j] + 1 && a[i] < a[j]) t[i] += t[j];
}
if(!t[i]) t[i] = 1;
}
for(int i = 1;i <= n;i ++)
if(f[i] == ans) cnt += t[i];
cout << ans << " ";
printf("%.0Lf", cnt);
return 0;
}