[NOIP模拟2015.10.06]C

题目大意

定义 S 为十进制只由4和7组成的全体正整数的集合。
给定数列 {an} ,要求支持以下两个操作。
add(l,r,x) :将所有 ai(lir) 加上 x
count(l,r) :求 |{i|lir,aiS}|

1n,m100000,1ai,x10000
所有操作结束后,保证 1ai10000

题目分析

发现点什么

分析题目,观察条件。所有操作后保证 a 数组每个数是小于等于 10000 的正整数,且初值也是小于等于 10000 的正整数,并且加的数大于 0 这说明了什么?每次操作结束之后 ai 都小于等于 10000 .
我们根据组合数知识,算出 10000 以内 S 集合的数有 30(=24+23+22+2) 个,设这个总数为 k

分块大法

分块大法好!分块大法好!分块大法好!(很重要说三遍)
我们考虑分块算法,设每块大小为 b ,我们在块内用数组 t 维护每个数出现次数。
执行修改操作时:对于块外的数,我们可以直接重构整个块,时间复杂度为 O(b) 。对于连续的块,我们可以将修改值加进块上标记里,时间复杂度 O(nb)
执行查询操作时:对于块外的数,我们可以直接重构整个块,然后暴力统计,时间复杂度 O(b) 。对于连续的块,设某个块标记为 +Δx ,那么我们可以统计 iStiΔx ,时间复杂度为 O(nkb)
然后总的时间复杂度为 O(m(b+nkb)) ,当 b=nk 时,时间复杂度最优,为 O(mnk)

代码实现

#include <iostream>
#include <cstdio>
#include <cmath>

using namespace std;

const int B=1800;
const int A=10000;
const int K=30;
const int N=100000;

bool iss[A+1];
int a[N+1];
int s[K+1];
int n,m,b,cnt;

struct block
{
    int l,r,mark;
    int bin[A+1];

    inline void rebuild()
    {
        if (!mark)
            return;
        for (int i=l;i<=r;i++)
            bin[a[i]]--;
        for (int i=l;i<=r;i++)
        {
            a[i]+=mark;
            bin[a[i]]++;
        }
        mark=0;
    }

    inline int query(int st,int en)
    {
        rebuild();
        int ret=0;
        for (int i=st;i<=en;i++)
            ret+=iss[a[i]];
        return ret;
    }

    inline void change(int st,int en,int edit)
    {
        rebuild();
        int ret=0;
        for (int i=st;i<=en;i++)
        {
            bin[a[i]]--;
            a[i]+=edit;
            bin[a[i]]++;
        }
    }
}bs[B+1];

inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while (ch<'0'||ch>'9')
    {
        if (ch=='-')
            f=-1;
        ch=getchar();
    }
    while (ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}

inline bool check(int x)
{
    while (x)
    {
        if (x%10!=4&&x%10!=7)
            return false;
        x/=10;
    }
    return true;
}

inline void preparation()
{
    for (int i=1;i<=A;i++)
        if (check(i))
        {
            iss[i]=true;
            s[++s[0]]=i;
        }
}

int main()
{
    preparation();
    freopen("c.in","r",stdin);
    freopen("c.out","w",stdout);
    n=read(),m=read();
    for (int i=1;i<=n;i++)
        a[i]=read();
    b=floor(sqrt(n*K))+1;
    cnt=n/b;
    for (int i=1;i<=cnt;i++)
    {
        bs[i].l=(i-1)*b+1;
        bs[i].r=i*b;
        for (int j=bs[i].l;j<=bs[i].r;j++)
            bs[i].bin[a[j]]++;
    }
    if (n%b)
    {
        cnt++;
        bs[cnt].l=(cnt-1)*b+1;
        bs[cnt].r=n;
        for (int j=bs[cnt].l;j<=bs[cnt].r;j++)
            bs[cnt].bin[a[j]]++;
    }
    char oprt;
    int l,r,x;
    while (m--)
    {
        oprt=getchar();
        while (oprt!='a'&&oprt!='c')
            oprt=getchar();
        l=read(),r=read();
        if (oprt=='a')
        {
            x=read();
            int lt=(l-1)/b+1,rt=(r-1)/b+1;
            if (lt==rt)
            {
                bs[lt].change(l,r,x);
                continue;
            }
            if (l!=bs[lt].l)
            {
                bs[lt].change(l,bs[lt].r,x);
                lt++;
            }
            if (r!=bs[rt].r)
            {
                bs[rt].change(bs[rt].l,r,x);
                rt--;
            }
            for (int i=lt;i<=rt;i++)
                bs[i].mark+=x;
        }
        else
        {
            int lt=(l-1)/b+1,rt=(r-1)/b+1;
            if (lt==rt)
            {
                printf("%d\n",bs[lt].query(l,r));
                continue;
            }
            int ans=0;
            if (l!=bs[lt].l)
            {
                ans+=bs[lt].query(l,bs[lt].r);
                lt++;
            }
            if (r!=bs[rt].r)
            {
                ans+=bs[rt].query(bs[rt].l,r);
                rt--;
            }
            for (int i=lt;i<=rt;i++)
                for (int j=1;j<=K;j++)
                    if (s[j]>=bs[i].mark)
                        ans+=bs[i].bin[s[j]-bs[i].mark];
            printf("%d\n",ans);
        }
    }
    fclose(stdin);
    fclose(stdout);
    return 0;
}

你可能感兴趣的:(OI,暴力,分块算法)