noip模拟赛 街灯

Posted zbtrs

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了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\\n", 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\\n", 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\\n", ans);
    }

    return 0;
}

 

以上是关于noip模拟赛 街灯的主要内容,如果未能解决你的问题,请参考以下文章

街灯变成了平台,世界将会怎样

noip模拟赛 写代码

NOIp模拟赛binary

NOIP模拟赛16

NOIp模拟赛value

2017 10.25 NOIP模拟赛