• Luogu P5309 [Ynoi2012]D1T1


    小清新分块题,从头到尾都十分套路,和CXR大佬一起YY了一下就出来了

    首先套路地设个阈值(S),把修改的(x)分成大于(S)和小于等于(S)两部分,然后我们考虑分别求解这两部分


    (x>S)

    这个应该是比较简单的一部分了吧,我们考虑到此时要修改的数也就(frac{n}{x})个,所以可以大力修改

    但是如果用树状数组这样的东西来维护区间和那么复杂度就是修改(frac{n}{x}cdotlog n)的,而询问只有(O(log n)),很不平衡

    所以我们套路地用分块来维护单点修改,区间查询,这样这部分的总体复杂度就平衡到了(O(mcdot(sqrt n+frac{n}{S})))

    然后刚开始的初始化也可以交给这一部分,这都是比较清新的


    (xle S)

    说实话这部分其实也不难,因为我们仔细观察题目,每次修改的(yle x)

    那么也就意味这这次修改是把数组中所有下标(mod x)(y)同余的位置全部加了(z)

    我们考虑固定(x)时的询问,那么一段区间([l,r])其实包含了(lfloorfrac{r-l+1}{x} floor)个整个的区间,而这些区间内的和其实就是所有询问(x)固定的(z)的总和

    剩下的一部分也很好算,其实就是求一个(mod x)意义下的区间和(只用对(ymod x)位置增加)

    考虑到此时(x)的范围很小,因此我们大可以直接记一个前缀和,每次修改暴力修改整个后缀,这样复杂度总体是(O(mS))


    总体分析

    这个时候按照一般的套路我们总是取(S=sqrt n)来达到理论最优的复杂度平衡

    但是这里如果你这么写你可能就会得到TLE80的情况,其实是因为出题人为了卡暴力出了大量的(xle S)的数据,而我们的算法在这部分的常数特别大

    因此很简单,我们大可以调小(S)的值(推荐在([30,50])中),然后就可以轻松地通过此题顺手抢了个Rank233

    CODE

    #include<cstdio>
    #include<cctype>
    #include<cmath>
    #define RI register int
    #define CI const int&
    #define Tp template <typename T>
    using namespace std;
    const int N=200005,mod=1e9+7,S=40;
    int n,m,a[N],opt,x,y,z,size;
    class FileInputOutput
    {
        private:
            static const int S=1<<21;
            #define tc() (A==B&&(B=(A=Fin)+fread(Fin,1,S,stdin),A==B)?EOF:*A++)
            #define pc(ch) (Ftop<S?Fout[Ftop++]=ch:(fwrite(Fout,1,S,stdout),Fout[(Ftop=0)++]=ch))
            char Fin[S],Fout[S],*A,*B; int Ftop,pt[15];
        public:
            Tp inline void read(T& x)
            {
                x=0; char ch; while (!isdigit(ch=tc()));
                while (x=(x<<3)+(x<<1)+(ch&15),isdigit(ch=tc()));
            }
            Tp inline void write(T x)
            {
                if (!x) return (void)(pc('0'),pc('
    ')); RI ptop=0;
                while (x) pt[++ptop]=x%10,x/=10; while (ptop) pc(pt[ptop--]+48); pc('
    ');
            }
            inline void Fend(void)
            {
                fwrite(Fout,1,Ftop,stdout);
            }
            #undef tc
            #undef pc
    }F;
    inline void inc(int& x,CI y)
    {
        if ((x+=y)>=mod) x-=mod;
    }
    inline int sum(CI a,CI b)
    {
        int t=a+b; return t>=mod?t-mod:t;
    }
    inline int sub(CI a,CI b)
    {
        int t=a-b; return t<0?t+mod:t;
    }
    namespace Case1 //Solver for z>sqrt(n)
    {
        const int BLO=450; int sum[BLO],blk[N];
        inline void init(void)
        {
            for (RI i=1;i<=n;++i) inc(sum[blk[i]=(i-1)/size+1],a[i]);
        }
        inline void modify(CI x,CI y,CI z)
        {
            for (RI i=y;i<=n;i+=x) inc(a[i],z),inc(sum[blk[i]],z);
        }
        inline int BF(CI x,CI y,int ret=0)
        {
            for (RI i=x;i<=y;++i) inc(ret,a[i]); return ret;
        }
        inline int query(CI x,CI y,int ret=0)
        {
            if (blk[x]==blk[y]) return BF(x,y);
            inc(ret,BF(x,blk[x]*size)); inc(ret,BF((blk[y]-1)*size+1,y));
            for (RI i=blk[x]+1;i<blk[y];++i) inc(ret,sum[i]); return ret;
        }
    };
    namespace Case2 //Solver for z<=sqrt(n)
    {
        int mv[S+5][S+5],sum[S+5],stack[N],top; bool vis[S+5];
        inline void modify(CI x,CI y,CI z)
        {
            if (!vis[x]) vis[x]=1,stack[++top]=x;
            for (RI i=y%x;i<x;++i) inc(mv[x][i],z); inc(sum[x],z);
        }
        inline int query(CI x,CI y,int ret=0)
        {
            for (RI i=1;i<=top;++i)
            {
                int p=stack[i],t=(y-x+1)/p; inc(ret,1LL*t*sum[p]%mod);
                int l=x+t*p,r=y; if (l>r) continue; l%=p; r%=p;
                if (l<=r) inc(ret,sub(mv[p][r],l?mv[p][l-1]:0)); else
                inc(ret,mv[p][r]),inc(ret,sub(sum[p],l?mv[p][l-1]:0));
            }
            return ret;
        }
    };
    int main()
    {
        //freopen("CODE.in","r",stdin); freopen("CODE.out","w",stdout);
        RI i; for (F.read(n),F.read(m),i=1;i<=n;++i) F.read(a[i]);
        for (size=(int)sqrt(n),Case1::init();m;--m)
        {
            F.read(opt); F.read(x); F.read(y);
            if (opt^1) F.write(sum(Case1::query(x,y),Case2::query(x,y)));
            else F.read(z),x>S?(Case1::modify(x,y,z),0):(Case2::modify(x,y,z),0);
        }
        return F.Fend(),0;
    }
    
  • 相关阅读:
    Wireshark抓包工具使用教程以及常用抓包规则
    linux自带抓包工具tcpdump使用说明
    利用mmap /dev/mem 读写Linux内存
    使用mii-tool设置网卡速率
    LINUX命令之ETHTOOL用法详解
    ethtool 在 Linux 中的实现框架和应用
    IDEA 上传更新的代码到码云上
    如何选择开源许可证
    IDEA 安装完码云插件,运行报“Cannot run program "xxx":CreateProcess error=2,系统找不到指定的文件”
    beans.factory.BeanCreationException beans.factory.annotation.Autowired(required=true)
  • 原文地址:https://www.cnblogs.com/cjjsb/p/10748173.html
Copyright © 2020-2023  润新知