首页 > 其他分享 >「解题报告」CF1129D Isolation

「解题报告」CF1129D Isolation

时间:2023-04-15 17:04:32浏览次数:40  
标签:int CF1129D 解题 MAXN delta MAXB 维护 Isolation

水题,但是调了好久 qwq

显然是 DP,出现次数显然分块,那就数据结构优化 DP 呗。

我们可以维护出当前点到每个点这段区间内有多少个出现次数为 \(1\) 的数,这个右端点每拓展一位修改的左端点一定是连续的区间。分块维护这个东西,如果是散块暴力重构暴力加,如果是整块那给整块打个加标记。

发现,加标记的差值是 \(\pm 1\),那么我们可以对每一块动态维护 \(\le k - \Delta\) 的和,可以 \(O(1)\) 维护。然后剩下的就随便维护了。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 100005, B = 320, MAXB = 355, P = 998244353;
int n, k;
int a[MAXN];
int bl[MAXN], L[MAXB], R[MAXB];
int lst[MAXN], llst[MAXN];
int f[MAXN];
int c[MAXN];
struct Block {
    int a[MAXN], delta, sum;
    void add(int d, int v) {
        a[d] = (a[d] + v) % P;
        if (d <= k - delta) sum = (sum + v) % P;
    }
    void addDelta(int v) {
        if (v == 1) {
            if (k - delta >= 0 && k - delta <= n)
                sum = (sum - a[k - delta] + P) % P;
            delta++;
        } else if (v == -1) {
            delta--;
            if (k - delta >= 0 && k - delta <= n)
                sum = (sum + a[k - delta]) % P;
        }
    }
} b[MAXB];
void rebuild(int i) {
    int newsum = 0;
    for (int j = L[i]; j <= R[i]; j++) {
        b[i].add(c[j], P - f[j]);
        c[j] += b[i].delta;
        b[i].add(c[j], f[j]);
        if (c[j] <= k) newsum = (newsum + f[j]) % P;
    }
    b[i].delta = 0;
    b[i].sum = newsum;
}
void add(int l, int r, int v) {
    if (bl[l] == bl[r]) {
        rebuild(bl[l]);
        for (int i = l; i <= r; i++) {
            b[bl[l]].add(c[i], P - f[i]);
            c[i] += v;
            b[bl[l]].add(c[i], f[i]);
        }
    } else {
        rebuild(bl[l]);
        for (int i = l; i <= R[bl[l]]; i++) {
            b[bl[l]].add(c[i], P - f[i]);
            c[i] += v;
            b[bl[l]].add(c[i], f[i]);
        }
        rebuild(bl[r]);
        for (int i = L[bl[r]]; i <= r; i++) {
            b[bl[r]].add(c[i], P - f[i]);
            c[i] += v;
            b[bl[r]].add(c[i], f[i]);
        }
        for (int i = bl[l] + 1; i <= bl[r] - 1; i++) {
            b[i].addDelta(v);
        }
    }
}
void insert(int d) {
    rebuild(bl[d]);
    b[bl[d]].add(c[d], f[d]);
}
int query() {
    int ret = 0;
    for (int i = 1; i <= bl[n]; i++) {
        ret = (ret + b[i].sum) % P;
    }
    return ret;
}
int main() {
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; i++) {
        scanf("%d", &a[i]);
    }
    for (int l = 1, r, i = 1; l <= n; l = r + 1, i++) {
        r = min(n, r + B - 1);
        L[i] = l, R[i] = r;
        for (int j = l; j <= r; j++) {
            bl[j] = i;
        }
    }
    f[1] = 1;
    insert(1);
    for (int i = 1; i <= n; i++) {
        if (lst[a[i]]) {
            add(llst[a[i]] + 1, lst[a[i]], -1);
        }
        add(lst[a[i]] + 1, i, 1);
        llst[a[i]] = lst[a[i]], lst[a[i]] = i;
        f[i + 1] = query();
        if (i != n) insert(i + 1);
    }
    printf("%d\n", f[n + 1]);
    return 0;
}

标签:int,CF1129D,解题,MAXN,delta,MAXB,维护,Isolation
From: https://www.cnblogs.com/apjifengc/p/17321397.html

相关文章

  • CodeChef Starters 83 Division 1 解题报告
    CodeChefStarters83Division1题解\(\newcommand\v\mathrm\)\(\text{ByDaiRuiChen007}\)ContestLinkA.ConstructStringProblemLink题目大意给定长度为\(n\)的字符串\(S\),每次操作可以把三个相同的字符变成一个同样的字符(\(\texttt{ccc}\to\textttc\))求若......
  • 「解题报告」AGC001F Wide Swap
    首先题目给的限制条件很奇怪,下标差\(K\)而值域差\(1\)。我们变成逆排列,然后就转换成了下标差\(1\),值域差\(K\)了,每次操作就相当于交换相邻的两个差\(\geK\)的数。假设新的逆排列为\(Q_i\)。我们发现,假如存在两个数差\(<K\),那么它们的相对位置关系一定不变。那么我们现......
  • Sql Isolation Level
    隔离性(Isolation):与数据库中的事务隔离级别以及锁相关,多个用户可以对同一数据并发访问而又不破坏数据的正确性和完整性。但是并行事务的修改必须与其他并行事务的修改相互独立,隔离。但是在不同的隔离级别下,事务的读取操作可能得到的结果是不同的。隔离级别用于决定如何控制并......
  • 4.14训练解题报告
    比赛传送门\(\color{white}20230413Tainrnig\)A.IceCave题意:考虑糖豆人的蜂窝迷图中的一层,走过一个正常格子就会变成洞。给定当前地板局面(抽象成\(n\timesm\)矩阵),以及起点和终点,求是否能在终点位置掉到下一层。特殊地,本题不允许停留。起点终点可以相同。\(n,m\le500\)......
  • 「解题报告」CF1528F AmShZ Farm
    之前zzy讲题讲到的,今天在题单里看到了,就又做了下。首先发现,对于一个\(a\)数组,\(b\)数组的方案数就是\(a\)中每个数的出现次数的\(k\)次方加和。考虑如何将\(a\)数组的条件转化一下。贪心的想,对于一个\(a_i\),我们肯定要尽可能使得它最终的数尽可能小。那么我们考虑每......
  • Codeforces Round #289 Div. 2 解题报告 A.B.C.E
    A-MaximuminTable纯递推。代码如下:#include<iostream>#include<string.h>#include<math.h>#include<queue>#include<algorithm>#include<stdlib.h>#include<map>#include<set>#include<stdio.h>usingn......
  • Codeforces Round #290 (Div. 2) 解题报告 A.B.C.D.
    A-FoxAndSnake模拟。代码如下:#include<iostream>#include<string.h>#include<math.h>#include<queue>#include<algorithm>#include<stdlib.h>#include<map>#include<set>#include<stdio.h>usingnames......
  • Codeforces Round #287 (Div. 2) 解题报告 A.B.C.D.E
    这次的CF挺水的,当时B题犯了一个很SB的错误,浪费了好多时间,所以D和E也没来得及看。sad,。。A-AmrandMusic水题,从小的开始选。代码如下:#include<iostream>#include<string.h>#include<math.h>#include<queue>#include<algorithm>#include<stdlib.h>#include<map>......
  • Codeforces Round #305 (Div. 1) A.B.C 解题报告
    A.MikeandFrog枚举。先是找循环,然后很容易得出一个两元一次方程,然后可以发现解也是有循环节的,所以最小的那个肯定出现在一定范围内,否则就后面也不可能出现。假设两个变量为x,y,系数分别为z1,z2。很显然,两者的最小公倍数便是一个周期,所以如果枚举x的话,只需要枚举到z2就可......
  • 「解题报告」CF960G Bandit Blues
    无脑的APJ用最无脑的方法解题!!!做了两天图论脑子爆炸后的apj寻求精神慰藉首先考虑\(n\)一定是从前往后的最大值与从后往前的最大值,这样我们只需要求出长度为\(n\),有\(k\)个前缀最大值的排列数量,记作\(f_{n,k}\)。考虑每次将当前排列中的最大值与最大值后面的排列去掉,这......