首页 > 其他分享 >ABC262Ex Max Limited Sequence 题解

ABC262Ex Max Limited Sequence 题解

时间:2023-05-09 18:55:39浏览次数:49  
标签:pr Limited rs int 题解 sum mid ls ABC262Ex

题意

给定 \(m\) 个限制 \((l_i,r_i,p_i)\) 及 \(n,k\),求满足以下条件的长度为 \(n\) 的不同序列 \(a=(a_1,a_2,\cdots,a_n)\) 的数目。

  1. \(\forall i \in[1,n],0\leq a_i\leq k\)

  2. \(\forall i \in[1,m],\max \limits_{j\in[l_i, r_i]}a_j=p_i\)

P4229,但数据更强,目测只允许 \(O(m\log m)\) 或类似复杂度通过。


考虑将条件 2 中每个限制拆分为:

  • \(\exists j\in[l_i,r_i],a_j=p_i\)
  • \(\forall j\in[l_i,r_i],a_j\le p_i\)

即任意位置 \(j\) 的取值最多不能超过覆盖它的各个限制中 \(p\) 的最小值 \(c_j=\min_{i\in[1,m],j\in[l_i,r_i]}p_i\),同时对于每个限制,至少有一个位置取到 \(p_i\);因此,取到 \(p_i\) 的位置 \(j\) 一定满足 \(p_i=a_j\)。

对位置离散化后,利用线段树及标记永久化进行简单的区间取 \(\min\) 操作,则最后对于限制 \(i\), \(c_j=p_i\) 的位置 \(j\) 才有可能取值 \([0,p_i]\),而该限制覆盖的其它显然只能取到 \([0,q]\),且一定有 \(q<p\),故 \(a_j\le p_i\),即这些位置并不影响该限制的满足性。

综上所述,我们可以对 \(p\) 离散化,把覆盖后结果为 \(x\) 的部分单独取出并进行 DP,求出满足 \(p_i=x\) 的所有限制的方案数。所有 \(x\) 的方案数之积即为答案。

此处细节:

  1. 如果有 \(d\) 个位置不被任何限制覆盖,这些位置方案数为 \((k+1)^d\)。
  2. 如果一个限制 \(i\) 满足 \(\forall j\in[l_i,r_i],c_j < p_i\),则总方案数为 \(0\)。线段树维护 \(c_j\) 区间最大值即可。

将所有 \(c_j=x\) 的位置及 \(l,r\) 离散化后作为一个序列 \(a'=(a'_1,a'_2,\cdots.a'_t)\) 集中考虑。注意有些位置离散化后是一个长度大于 \(1\) 的连续段,设其长度为 \(v_i\)。

现在考虑如何在 \(O(t\log t)\) 时间内解决以下 DP 问题:

给定 \(m\) 个限制 \((l'_i,r'_i)\) 及 \(x\),求满足以下条件的序列个数:

  • \(\forall i \in[1,t],\max \limits_{j\in[l'_i, r'_i]}a'_j=x\)

不妨设 \(f_{i}\) 为分配前 \(i\) 位的方案数,\(g_{i,j}\) 为分配前 \(i\) 位,使得满足 \(a'_k=x\) 的最大的 \(k\) 等于 \(j\) 的方案数。

显然如果第 \(i\) 位并非必须取 \(x\),\(\forall j \in [1,i],g_{i,j}=x^{v_i}g_{i-1,j}\)。这个操作可以用线段树区间乘完成。

如果第 \(i\) 位取 \(x\),即 \(g_{i,i} = ((x+1)^{v_i} - x^{v_i})f_{i-1}\)。

如果不取,考虑若存在部分区间最后一个覆盖的位置为 \(i\),那么设这些区间左端点的最大值为 \(h_i\),则 \([h_i,i]\) 至少需取一个 \(x\)。所以 \(\forall j \in [1,h_i-1],g_{i,j} = 0\)。线段树维护区间推平即可。

综上所述,\(f_i=g_{i,i}+x^{v_i}\sum^{i-1}_{j=h_i}g_{i,j}\)。区间和也可用线段树维护。

此处细节:

  1. 需取模,计算可能出现负数。
  2. 离散化后序列相邻两项在原序列不一定连续。

目标:\(f_t\)。答案:\((k+1)^d\prod_{x\in p}f_t\)。时间复杂度 \(O(m\log m)\),空间线性。


#include <bits/stdc++.h>
#define maxm 400005
#define inf 0x3f3f3f3f
#define ad(i, j) i = (i % mod + j % mod + mod) % mod
#define mu(i, j) i = (i * j) % mod
#define ls(p) (p << 1)
#define rs(p) ((p << 1) + 1)
using namespace std;

const int mod = 998244353;
int n, m, k, num, nx, nf, b[maxm], bx[maxm];
int c[maxm];
struct Query {
    int l, r, x;
} a[maxm];
vector<int> q[maxm], v[maxm];
inline bool cmp(int i, int j) { return a[i].r == a[j].r ? a[i].l > a[j].l : a[i].r < a[j].r; }
long long ans, f[maxm], g[maxm];
// Basic
inline int len(int x) { return (x & 1) ? (b[(x >> 1) + 1] - b[x >> 1] - 1) : 1; }
inline int qpow(int x, int p) {
    if (!p) return 1;
    long long tx = qpow(x, p >> 1);
    return (p & 1) ? (tx * tx % mod * x % mod) : (tx * tx % mod);
}
// BIT
namespace Seg {
struct SegTree {
    long long sum, mul, cov;
} t[maxm * 4];
void build(int p, int l, int r) {
    t[p] = {g[l], 1, -1};
    if (l < r) {
        int mid = (l + r) >> 1;
        build(ls(p), l, mid), build(rs(p), mid + 1, r);
        t[p].sum = (t[ls(p)].sum + t[rs(p)].sum) % mod;
    }
}
inline void spread(int p) {
    if (~t[p].cov) {
        t[ls(p)].sum = t[ls(p)].cov = t[rs(p)].sum = t[rs(p)].cov = t[p].cov;
        t[ls(p)].mul = t[rs(p)].mul = 1;
        t[p].cov = -1;
    }
    if (t[p].mul > 1) {
        mu(t[ls(p)].sum, t[p].mul), mu(t[rs(p)].sum, t[p].mul);
        mu(t[ls(p)].mul, t[p].mul), mu(t[rs(p)].mul, t[p].mul);
        t[p].mul = 1;
    }
}
void change(int p, int pl, int pr, int l, int r, int x, int tg = 0) {
    if (l > r) return;
    if (pl >= l && pr <= r) {
        if (tg) t[p].mul = 1, t[p].sum = t[p].cov = x;
        else mu(t[p].mul, x), mu(t[p].sum, x);
    } else {
        spread(p);
        int mid = (pl + pr) >> 1;
        if (l <= mid) change(ls(p), pl, mid, l, r, x, tg);
        if (r > mid) change(rs(p), mid + 1, pr, l, r, x, tg);
        t[p].sum = (t[ls(p)].sum + t[rs(p)].sum) % mod;
    }
}
long long ask(int p, int pl, int pr, int l, int r) {
    if (l > r) return 0;
    else if (pl >= l && pr <= r) return t[p].sum;
    spread(p);
    int mid = (pl + pr) >> 1;
    long long ans = 0;
    if (l <= mid) ad(ans, ask(ls(p), pl, mid, l, r));
    if (r > mid) ad(ans, ask(rs(p), mid + 1, pr, l, r));
    return ans;
}
};
namespace Mn {
int ma[maxm * 4], tg[maxm * 4];
inline void init() { memset(tg, 0x3f, sizeof(tg)); }
void cover(int p, int pl, int pr, int l, int r, int x) {
    if (pl >= l && pr <= r) tg[p] = min(tg[p], x);
    else {
        int mid = (pl + pr) >> 1;
        if (l <= mid) cover(ls(p), pl, mid, l, r, x);
        if (r > mid) cover(rs(p), mid + 1, pr, l, r, x);
    }
}
void dfs(int p, int l, int r, int x) {
    int mid = (l + r) >> 1;
    x = min(x, tg[p]);
    if (l == r) c[l] = x, ma[p] = len(l) ? x : 0;
    else dfs(ls(p), l, mid, x), dfs(rs(p), mid + 1, r, x), ma[p] = max(ma[ls(p)], ma[rs(p)]);
}
int ask(int p, int pl, int pr, int l, int r) {
    if (pl >= l && pr <= r) return ma[p];
    int mid = (pl + pr) >> 1, ans = 0;
    if (l <= mid) ans = max(ans, ask(ls(p), pl, mid, l, r));
    if (r > mid) ans = max(ans, ask(rs(p), mid + 1, pr, l, r));
    return ans;
}
};
signed main() {
    ans = 1, num = nx = 0;
    scanf("%d%d%d", &n, &k, &m), ++k;
    for (int i = 1; i <= m; ++i) {
        scanf("%d%d%d", &a[i].l, &a[i].r, &a[i].x), ++a[i].x;
        b[++num] = a[i].l, b[++num] = a[i].r, bx[++nx] = a[i].x;
    }
    sort(b + 1, b + 1 + num), num = unique(b + 1, b + 1 + num) - b - 1;
    sort(bx + 1, bx + 1 + nx), nx = unique(bx + 1, bx + 1 + nx) - bx - 1;
    b[num + 1] = n + 1, n = num * 2 + 1;
    Mn::init();
    for (int i = 1; i <= m; ++i) {
        a[i].l = (lower_bound(b + 1, b + 1 + num, a[i].l) - b) << 1;
        a[i].r = (lower_bound(b + 1, b + 1 + num, a[i].r) - b) << 1;
        a[i].x = lower_bound(bx + 1, bx + 1 + nx, a[i].x) - bx;
        q[a[i].x].push_back(i);
        Mn::cover(1, 1, n, a[i].l, a[i].r, a[i].x);
    }
    Mn::dfs(1, 1, n, inf);
    // 3 m log m
    for (int i = 1; i <= m; ++i)
        if (Mn::ask(1, 1, n, a[i].l, a[i].r) < a[i].x) {
            puts("0");
            return 0;
        }
    for (int i = 1; i <= n; ++i)
        if (c[i] < inf && len(i)) v[c[i]].push_back(i);
        else if (len(i)) mu(ans, qpow(k, len(i)));
    for (int x = 1; x <= nx; ++x) {
        nf = v[x].size();
        for (int i = 1; i <= nf; ++i) f[i] = g[i] = 0;
        sort(q[x].begin(), q[x].end(), cmp);
        Seg::build(1, 1, nf);
        int p = -1;
        f[0] = 1;
        for (int i = 1; i <= nf; ++i) {
            int ln = len(v[x][i - 1]);
            long long t = f[i - 1] * ((qpow(bx[x], ln) - qpow(bx[x] - 1, ln) + mod) % mod) % mod;
            int nxt = i < nf ? v[x][i] : inf, l = 0;
            while (p < int(q[x].size() - 1) && a[q[x][p + 1]].r < nxt) ++p, l = max(l, a[q[x][p]].l);
            if (l) {
                auto lp = lower_bound(v[x].begin(), v[x].end(), l);
                l = lp - v[x].begin() + 1;
            }
            if (!l) f[i] = f[i - 1] * qpow(bx[x], ln) % mod;
            else {
                f[i] = (t + Seg::ask(1, 1, nf, l, i - 1) * qpow(bx[x] - 1, ln) % mod) % mod;
                Seg::change(1, 1, nf, 1, l - 1, 0, 1);
            
            }
            Seg::change(1, 1, nf, i, i, t, 1);
            Seg::change(1, 1, nf, 1, i - 1, qpow(bx[x] - 1, ln));
        }
        mu(ans, f[nf]);
    }
    printf("%lld\n", ans);
    return 0;
}

标签:pr,Limited,rs,int,题解,sum,mid,ls,ABC262Ex
From: https://www.cnblogs.com/Muelsyse/p/17385964.html

相关文章

  • 【问题解决】Kafka报错 Bootstrap broker x.x.x.x:9092 (id: -1 rack: null) disconne
    问题复现近日针对某一客户需求开发了一个需要使用Kafka的功能,功能是什么暂且不论,在本地虚机的Kafka连接一切正常遂放到测试服务器上验证功能,以下是监听topic成功和警告报错:2023-05-0910:22:23[localhost-startStop-1]INFOorg.apache.kafka.clients.consumer.ConsumerConfig......
  • ABC191F 题解
    题目传送门题目分析我们发现,\(\text{min}\)操作实际上就是把两数当中较大的那个删除,较小的那个数不受影响,所以用最小的数删还是用另一个数删是无区别的。一个性质:\[\gcd(x,y)\le\min(x,y)\]不管\(a_{min}\)是原来的还是在\(\text{gcd}\)操作后新生成的,所以无论什么时......
  • ant-select数据会发生卡顿问题解决
    <a-selectv-model="form.region"show-searchplaceholder="请选择"option-filter-prop="children"@search="handleSearch"@popupScroll="handlePopu......
  • [AtCoder-AT_ABC070C]题解(C++)
    PartIPreface原题目(Luogu)原题目(AtCoder)PartIISketch给定一个正整数\(N(1\leqN\leq100)\),表示时钟数量。接下来\(N\)行,每行一个正整数\(T_i(1\leqT_i\leq10^{18})\),表示每个时钟旋转\(T_i\)秒后还会回到原来的地方。求出在多少秒之后,所有时钟还会同时......
  • xshell7 免费版 关闭 弹窗问题解决
    原博客地址:https://www.hao.kim/1175.html使用二进制编辑器winhex进行编辑绿色版下载地址:https://mikemhm.lanzoul.com/i6boy0v2a6pa使用winhex打开xshell.exe文件xshell.exe默认目录"C:\ProgramFiles(x86)\NetSarang\Xshell7\Xshell.exe"查找16进制数值74116A006A0......
  • [AtCoder-AT_ABC070_A]题解(C++)
    PartIPreface原题目(Luogu)原题目(AtCoder)PartIISketch给定一个正整数\(n(100\leqn\leq999)\)。求\(n\)是否是一个回文数,是输出\(\texttt{Yes}\),不是输出\(\texttt{No}\)。PartIIIAnalysisSolve1如果仔细观察的话,应该都能发现,\(n\)一定是一个三位数。......
  • P8714 题解
    洛谷P8714题意自己看(思路分五个小题去考虑。问题A枚举门牌号,看门牌号中有多少个\(2\),统计答案即可。voidsloveA(){//问题Aintsum=0;for(inti=1,j;i<=2020;i++){//枚举门牌号j=i;while(j){//枚举每一位sum+=(j%10......
  • 第十四届蓝桥杯省赛C++ B组(个人经历 + 题解)
    参赛感受这是我第一次参加蓝桥杯的省赛,虽然没什么参赛经验,但是自己做了很多前几届蓝桥杯的题,不得不说,这一届蓝桥杯省赛的难度相较于之前而言还是比较大的。之前很流行蓝桥杯就是暴力杯的说法,但是随着参赛人数的增多,比赛认可度的提升,比赛题目的质量也明显越来越高了。这次省赛涉及......
  • CF920E Connected Components? 题解
    一道线段树优化建图好题(大雾扣掉一些边看起来不好做,我们直接大力加上存在的边,然后跑连通块。对于一个点,如果他被扣掉了\(k\)个邻居,那么没扣掉的那些形成了至多\(k+1\)个连续段,可以用线段树优化建图向每个连续段各用\(\log\)的代价连边。由于总共扣掉了\(m\)条边,所以总共......
  • 装最多水的容器 - 题解
    1.问题描述  原题的地址见:ContainerWithMostWater-LeetCode.此问题等价于如下问题:    给定所有元素非负的数组[a0,a1,...,an-1],计算(j-i)|aj-ai|(其中j>i)的最小值。 2.暴力解法  有了问题的描述,很容易写出暴力求解的算法:intmaxArea(vector<int>......