[题解] [洛谷P1108] 低价购买
[洛谷P1108] 低价购买
题目描述#
给定一个序列,求这个序列的最长严格下降子序列的长度和数量,特别的是如果两个子序列只要每个数都相同,无论原来的位置,都算作同一个子序列。
输入格式#
第一行共一个整数
第二行一行
输出格式#
输出共一行两个整数,分别为最大购买次数和拥有最大购买次数的方案数(数据保证
题解#
水蓝题一道。数据范围允许
问题的关键是如何统计出得到
最后剩下的问题就是重复的方案,实际上这中情况仅限于前一个状态对应的最后一位
AC代码#
#include <iostream>
#define int long long
using namespace std;
const int MAXN = 5003;
const int MAXA = 1e5 + 3;
int n, a[MAXN];
int f[MAXN], cnt[MAXN]; // 分别记录长度和方案数
int vis[MAXA]; // 标记是否出现过相同状态
signed main() {
cin >> n;
// 输入与初始化
for (int i = 1; i <= n; i++) {
cin >> a[i];
cnt[i] = f[i] = 1;
}
int ans = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j < i; j++) vis[a[j]] = 0; // 重置标记
for (int j = i - 1; j > 0; j--) {
if (a[i] < a[j]) { // 合法的状态
if (f[j] + 1 > f[i]) { // 更优的状态转移
f[i] = f[j] + 1;
// 继承方案数
vis[a[j]] = f[i];
cnt[i] = cnt[j];
} else if (f[j] + 1 == f[i]) { // 与当前状态一样优的状态
// 累加方案数
if (vis[a[j]] != f[i]) cnt[i] += cnt[j]; // 不是相同的状态就累加方案数
vis[a[j]] = f[i];
}
}
}
ans = max(ans, f[i]); // 更新答案
}
int anscnt = 0; // 统计方案数
for (int i = 1; i <= n; i++) vis[a[i]] = false; // 初始化标记
for (int i = n; i > 0; i--) {
if (vis[a[i]]) continue; // 如果统计过相同的状态就跳过
if (f[i] == ans) anscnt += cnt[i], vis[a[i]] = true; // 如果是最优状态就累加到答案里
}
// 输出答案
cout << ans << ' ' << anscnt << '\n';
return 0;
}
分类:
ICPC日常练习
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】