zoukankan      html  css  js  c++  java
  • noip模拟赛 街灯

    分析:对于前30%的数据直接暴力模拟即可,对于另外30%的数据,因为每次的p是一样的,所以可以用莫队来维护,先离散化一下,再用一个桶统计次数.

          100%的做法和之前做过的一道模拟赛题很像,当模数很小的时候分块,否则就暴力修改.其实看到区间操作第一感觉是线段树,但是线段树并不能维护这个,分块维护的信息多一些,所以分块.在模数较小的时候记录一下第i个块,模p等于v的有多少个,即g[i][p][v],利用前缀和统计1~i个块的个数.在模数较大的时候因为只有v,v+p,v+2p对答案有影响,所以记录第i个块值为v的有多少个,即f[i][v],同样也可以用前缀和处理一下.查询的时候还是分模数的大小来进行,先统计完整包含在块里面的,在暴力统计在块外面的就可以了.

          当有些信息线段树维护不了的时候可以考虑一下分块,分块的时候可以根据范围来决定什么时候分块,什么时候用其它的方法,前缀和可以加速区间查询操作.

    60分暴力:

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    int n, m, a[1000010], b[1000010], cnt, tot, c[1000100], sizee, L = 1, R = 0, tong[1000010], ans[1000010];
    bool flag = true;
    
    struct node
    {
        int l, r, p, v,id;
    }e[100010];
    
    bool cmp(node a, node b)
    {
        if (a.l / sizee == b.l / sizee)
            return a.r < b.r;
        return a.l < b.l;
    }
    
    void add(int x)
    {
        tong[a[x]]++;
    }
    
    void del(int x)
    {
        tong[a[x]]--;
    }
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
            scanf("%d", &a[i]);
        cnt = 0;
        for (int i = 1; i <= m; i++)
        {
            scanf("%d%d%d%d", &e[i].l, &e[i].r, &e[i].p, &e[i].v);
            e[i].id = i;
            if (i != 1 && e[i].p != e[i - 1].p)
                flag = false;
            b[++cnt] = e[i].v;
        }
        if (flag)
        {
            for (int i = 1; i <= n; i++)
            {
                a[i] %= e[1].p;
                b[++cnt] = a[i];
            }
            memcpy(c, b, sizeof(b));
            sort(c + 1, c + 1 + cnt);
            tot = unique(c + 1, c + 1 + cnt) - c - 1;
            for (int i = 1; i <= n; i++)
                a[i] = lower_bound(c + 1, c + 1 + tot, a[i]) - c - 1;
            for (int i = 1; i <= m; i++)
                e[i].v = lower_bound(c + 1, c + 1 + tot, e[i].v) - c - 1;
            sizee = (int)sqrt(n);
            sort(e + 1, e + 1 + m, cmp);
            for (int i = 1; i <= m; i++)
            {
                int l = e[i].l, r = e[i].r;
                while (R < r)
                    add(++R);
                while (R > r)
                    del(R--);
                while (L > l)
                    add(--L);
                while (L < l)
                    del(L++);
                ans[e[i].id] = tong[e[i].v];
            }
            for (int i = 1; i <= m; i++)
                printf("%d
    ", ans[i]);
        }
        else
        {
            for (int i = 1; i <= m; i++)
            {
                int cnt = 0;
                for (int j = e[i].l; j <= e[i].r; j++)
                    if (a[j] % e[i].p == e[i].v)
                        cnt++;
                printf("%d
    ", cnt);
            }
        }
    
        return 0;
    }

    100分正解:

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    int n, m, a[100010], maxn, block, cnt, maxx, l[10010], r[10010], ans;
    int f[1010][10010], g[1010][70][70], kuai[100100];
    
    int main()
    {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++)
        {
            scanf("%d", &a[i]);
            maxn = max(maxn, a[i]);
        }
        block = 100;
        cnt = (n - 1) / block + 1;
        maxx = 60;
        for (int i = 1; i <= cnt; i++)
        {
            l[i] = (i - 1) * block + 1, r[i] = min(n, i * block);
            for (int j = 0; j <= maxn; j++)
                f[i][j] = f[i - 1][j];
            for (int j = 1; j <= maxx; j++)
                for (int k = 0; k < maxx; k++)
                    g[i][j][k] = g[i - 1][j][k];
            for (int j = l[i]; j <= r[i]; j++)
            {
                kuai[j] = i;
                f[i][a[j]]++;
                for (int k = 1; k <= maxx; k++)
                    g[i][k][a[j] % k]++;
            }
        }
        for (int i = 1; i <= m; i++)
        {
            int ll, rr, p, v;
            scanf("%d%d%d%d", &ll, &rr, &p, &v);
            ans = 0;
            v %= p;
            int L = kuai[ll], R = kuai[rr];
            if (L < R)
            {
                if (p <= 60)
                    ans += g[R - 1][p][v] - g[L][p][v];
                else
                    for (int i = v; i <= maxn; i += p)
                        ans += f[R - 1][i] - f[L][i];
                for (int j = ll; j <= r[L]; j++)
                    if (a[j] % p == v)
                        ans++;
                for (int j = l[R]; j <= rr; j++)
                    if (a[j] % p == v)
                        ans++;
            }
            else
                for (int j = ll; j <= rr; j++)
                    if (a[j] % p == v)
                        ans++;
            printf("%d
    ", ans);
        }
    
        return 0;
    }
  • 相关阅读:
    Jenkins理解逻辑图
    什么是Jenkins?
    SpringBoot Test及注解详解
    如何熟悉一个新项目
    调用百度OCR模块进行文字识别
    python安装包的方法&安装遇到的问题总结_2020_11_19
    怎么让谷歌浏览器记住密码(不需要任何插件)
    excel以一列数据为x一列为y作折线图
    java创建新java文件的方法
    Mathematics释放变量的方法
  • 原文地址:https://www.cnblogs.com/zbtrs/p/7764387.html
Copyright © 2011-2022 走看看