1 条题解
-
0
思路与算法
对电阻离散化,在Fenwick节点中保存(最长长度,方案数)。合并时长度大者优先,相同长度把方案数相加。对每个位置只查询严格小于该电阻的前缀,空前缀视为长度0且有一种空方案,然后长度加1并更新;最终取全部值前缀。
正确性说明
每条上升子序列按末位置唯一分类;当前元素的合法前驱恰是此前较小电阻。按长度取优及同长求和完整保留全部最长前驱,添加当前元素得到的序列互异。Fenwick只分解不相交值区间,聚合无重计,因此输出全局LIS及计数。
复杂度
读入和排序压缩O(NlogN),Fenwick初始化O(N),每位置查询更新O(logN),总O(NlogN)时间,O(N)空间。
易错点
相同电阻不能接续,查询秩-1。相同值不同位置属于不同方案,可在更新中累加。type=0只输出长度,type=1另输出模123456789计数。
参考代码(C++11)
#include <bits/stdc++.h> using namespace std; const int MOD = 123456789; struct Val { int len, cnt; }; Val merge(Val a, Val b) { if (a.len != b.len) return a.len > b.len ? a : b; return {a.len, (a.cnt + b.cnt) % MOD}; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n, type; cin >> n >> type; vector<long long> a(n), b; for (auto &x : a) cin >> x; b = a; sort(b.begin(), b.end()); b.erase(unique(b.begin(), b.end()), b.end()); vector<Val> t(b.size() + 1, {0, 0}); for (long long v : a) { int x = lower_bound(b.begin(), b.end(), v) - b.begin() + 1; Val z = {0, 0}; for (int i = x - 1; i; i -= i & -i) z = merge(z, t[i]); if (!z.len) z.cnt = 1; z.len++; for (int i = x; i < (int)t.size(); i += i & -i) t[i] = merge(t[i], z); } Val ans = {0, 0}; for (int i = b.size(); i; i -= i & -i) ans = merge(ans, t[i]); cout << ans.len << '\n'; if (type) cout << ans.cnt << '\n'; }
- 1