1 条题解

  • 0
    @ 2026-10-26 17:31:10

    思路与算法

    对电阻离散化,在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

    信息

    ID
    1810
    时间
    1000ms
    内存
    256MiB
    难度
    普及
    标签
    递交数
    1
    已通过
    1
    上传者