zoukankan      html  css  js  c++  java
  • Codeforces Round #542 [Alex Lopashev Thanks-Round] (Div. 1) D. Isolation

    题目链接

    题目大意

    将一段长为(n)的序列(a)分为几个的非空段,每段中只出现一次的数的个数不得大于(k)
    求方案数。

    Solution

    暴力比较显然,设(f[i])表示以(i)作为一段结尾的方案数。
    (f[i]=sum_{j=1}^{i-1}f[j]) ((cnt(j+1,i)leq k))
    其中(cnt(j,i))表示(j)(i)中出现次数为1的数的个数。

    然后考虑怎么优化,
    可以发现,每次新加入一个数(a[i])(cnt)改变的是连段连续的区域,
    (s[j])表示(cnt(j, i))(pre[i])表示位置(i)前第一个(a[i])的位置,
    那么(pre[pre[i]] + 1)(pre[i])(s) -1,(pre[i] + 1)(i)(s) +1。

    于是我们想到了暴力美学——分块。
    (我的是比较劣的方法,时间复杂度大概是(O(nsqrt{n}log(sqrt{n})))。)
    (tag[j])表示块(j)全体元素的(s)需要改变的值。
    (s[i])为关键字将块内元素排序。
    每次加入(a[i]),就先更新之前的(s),整块就之间改变(tag),不完整的块就(rebuild)
    更新(f[i]),对于(i)所在的块暴力枚举(i)之前的元素,
    对于前面的块,可以加入(f[i])的就是(f[j]) ((s[j] + tag[j所在的块] leq k))
    由于块内元素已根据(s[i])排序,那么我们用二分 + 前缀和维护就可以了。
    最后答案是(f[n])

    然后无。

    Code

    #include <cstdio>
    #include <algorithm>
    #include <cmath>
    
    using namespace std;
    
    #define N 100000
    #define M 320
    #define Mod 998244353
    
    #define fo(i, x, y) for(int i = x; i <= y; i ++)
    #define fd(i, x, y) for(int i = x; i >= y; i --)
    
    void read(int &x) {
        char ch = getchar(); x = 0;
        while (ch < '0' || ch > '9') ch = getchar();
        while (ch >= '0' && ch <= '9') x = (x << 1) + (x << 3) + ch - 48, ch = getchar();
    }
    
    struct Arr { int x, y; } b[N + 1], c[M + 1];
    
    int a[N + 1], s[N + 1], add[M + 1], pre[N + 1][2], num[N + 1];
    
    int f[N + 1], sum[N + 1];
    
    int n, m, tot, sq;
    
    bool Cmp(Arr a, Arr b) { return a.x < b.x; }
    
    int Max(int x, int y) { return x > y ? x : y; }
    
    int Min(int x, int y) { return x < y ? x : y; }
    
    void Rebuild(int k, int l, int r, int ad) {
        fo(i, c[k].x, c[k].y) s[i] += add[k];
        fo(i, l, r) s[i] += ad;
        add[k] = 0;
    
        fo(i, c[k].x, c[k].y) b[i] = (Arr) { s[i], f[i - 1] };
        sort(b + c[k].x, b + 1 + c[k].y, Cmp);
    
        sum[c[k].x] = b[c[k].x].y;
        fo(i, c[k].x + 1, c[k].y) sum[i] = (sum[i - 1] + b[i].y) % Mod;
    }
    
    void Add(int l, int r, int ad) {
        fo(i, 1, tot) {
            if (c[i].x > r) break;
            if (c[i].y >= l && c[i].x <= r) {
                if (c[i].x < l) Rebuild(i, l, Min(c[i].y, r), ad);
                else if (c[i].y > r)  Rebuild(i, Max(i, c[i].x), r, ad);
                else (add[i] += ad);
            }
        }
    }
    
    int Get(int l, int r, int g) {
        int mid = 0, w = 0;
        while (l <= r) {
            mid = l + r >> 1;
            b[mid].x <= g ? l = (w = mid) + 1 : r = mid - 1;
        }
        return w;
    }
    
    int main() {
        freopen("isolation.in", "r", stdin);
        freopen("isolation.out", "w", stdout);
    
        read(n), read(m);
        fo(i, 1, n) read(a[i]);
    
        sq = sqrt(n); tot = n / sq + (n % sq > 0);
        fo(i, 1, n) num[i] = (i - 1) / sq + 1;
        fo(i, 1, n) if (num[i] > num[i - 1])
            c[num[i]].x = i, c[num[i - 1]].y = i - 1;
        c[num[n]].y = n;
        fo(i, 0, n) f[i] = 0;
        f[0] = 1;
        fo(i, 1, n) {
            int k = num[i];
            if (pre[a[i]][0]) {
                if (pre[a[i]][1] + 1 >= c[k].x) {
                    fo(j, pre[a[i]][1] + 1, pre[a[i]][0]) -- s[j];
                    fo(j, pre[a[i]][0] + 1, i) ++ s[j];
                    Rebuild(k, 1, 0, 0);
                } else if (pre[a[i]][0] >= c[k].x) {
                    Add(pre[a[i]][1] + 1, c[k].x - 1, -1);
                    fo(j, c[k].x, pre[a[i]][0]) -- s[j];
                    fo(j, pre[a[i]][0] + 1, i) ++ s[j];
                    Rebuild(k, 1, 0, 0);
                } else {
                    Add(pre[a[i]][1] + 1, pre[a[i]][0], -1), Add(pre[a[i]][0] + 1, c[k].x - 1, 1);
                    fo(j, c[k].x, i) ++ s[j];
                    Rebuild(k, 1, 0, 0);
                }
            } else {
                Add(1, c[k].x - 1, 1);
                fo(j, c[k].x, i) ++ s[j];
                Rebuild(k, 1, 0, 0);
            }
            pre[a[i]][1] = pre[a[i]][0], pre[a[i]][0] = i;
            fo(j, c[k].x, i) if (s[j] + add[k] <= m) (f[i] += f[j - 1]) %= Mod;
    
            fd(j, k - 1, 1) {
                if (b[c[j].x].x + add[j] <= m)
                    (f[i] += sum[Get(c[j].x, c[j].y, m - add[j])]) %= Mod;
            }
            if (i == c[k].y) Rebuild(k, 1, 0, 0);
        }
    
        printf("%d
    ", f[n]);
    
        return 0;
    }
    
    
  • 相关阅读:
    现在有很多第三方的SDK来做直播,那么我们改选择哪一种?
    移动直播app怎么做
    服务器上如何再另外添加一个E盘
    服务器上如何将D盘修改为E盘
    修改数据库中的内容报错:PropertyAccessException:Null value was assinged to a property of primitive type setter of
    怎样才能做好SNS社区网站
    Linux服务器上如何设置MySQL的max_allowed_packe
    [AST Eslint] No console with schema options && isPrimitive
    [Javascript] Deep partial equal Object LooksLike
    [AST Eslint] No Console allowed
  • 原文地址:https://www.cnblogs.com/zhouzj2004/p/13777880.html
Copyright © 2011-2022 走看看