zoukankan      html  css  js  c++  java
  • dtoi3031 交错和查询 (sum)

    题意:

         有一个长度很大(10^18)的序列是由长度为n的序列不断循环构成的。长度为n的序列给定且数值均为0~9。每次有两个操作。

         1 修改循环节上的一位。

         2 询问 $[l,r]$ 内所有连续子串的交错和的和,$1<=l,r<=10^{18}$。

         一个子串$[l,r]$的交错和$=a[l]-a[l+1]+a[l+2]-...+(-1)^{r-l}a[r]$。

    题解:

         先考虑l,r都小于等于n的情况。考虑对于[l,r]中的一个位置i,它对答案(这里当然指所有连续子串)的贡献。显然,如果i是奇数位,那么贡献就是a[i]*(r-i+1),否则就是0,因为前面一加一减的就抵消了。那么可以使用线段树维护,我们需要维护的值有:奇数位的和,偶数位的和,奇数位的贡献,偶数位的贡献,以及长度。合并的时候分类讨论一下即可。

         那么当l和r很大的时候怎么办呢,其实跟上面的做法一样,只不过现在我们需要维护很多个完整的序列拼在一起的答案。可以使用倍增,合并的方法与线段树节点合并方法一样。最后我们只需要把前一部分+中间一堆重复的完整的序列+末尾一部分的三个部分合并即可求出答案。本题的核心在于合并,因为程序中每一个地方的合并都是相同的方法。

    #include<cstdio>
    #include<algorithm>
    #include<cstdlib>
    using namespace std;
    const int mod=1e9+7;
    int n,m;
    char s[200002];
    typedef struct{
        long long ans1,ans2,s1,s2,len;
    }P;
    P p[800002],ans,t[70];
    long long read(){
        long long f=0;char ch=getchar();
        while(ch<'0' || ch>'9')ch=getchar();
        while(ch>='0' && ch<='9'){f=f*10+ch-48;ch=getchar();}
        return f;
    }
    P hb(P a,P b){
        P t;
        if (a.len%2)
        {
            t.ans1=(a.s1*(b.len%mod)%mod+a.ans1+b.ans2);
            t.ans2=(a.s2*(b.len%mod)%mod+a.ans2+b.ans1);
            t.s1=a.s1+b.s2;t.s2=a.s2+b.s1;
        }
        else
        {
            t.ans1=(a.s1*(b.len%mod)%mod+a.ans1+b.ans1);
            t.ans2=(a.s2*(b.len%mod)%mod+a.ans2+b.ans2);
            t.s1=a.s1+b.s1;t.s2=a.s2+b.s2;
        }
        t.ans1%=mod;t.ans2%=mod;t.s1%=mod;t.s2%=mod;
        t.len=a.len+b.len;
        return t;
    }
    void build(int root,int begin,int end){
        if (begin==end)
        {
            int z=s[begin]-'0';
            p[root].ans1=p[root].s1=z;p[root].ans2=p[root].s2=0;p[root].len=1;
            return;
        }
        int mid=(begin+end)/2;
        build(root*2,begin,mid);build(root*2+1,mid+1,end);
        p[root]=hb(p[root*2],p[root*2+1]);
    }
    void gengxin(int root,int begin,int end,int wz,int z){
        if (begin>wz || end<wz)return;
        if (begin==end)
        {
            p[root].ans1=p[root].s1=z;p[root].ans2=p[root].s2=0;p[root].len=1;
            return;
        }
        int mid=(begin+end)/2;
        gengxin(root*2,begin,mid,wz,z);gengxin(root*2+1,mid+1,end,wz,z);
        p[root]=hb(p[root*2],p[root*2+1]);
    }
    void chaxun(int root,int begin,int end,int begin2,int end2){
        if (begin>end2 || end<begin2)return;
        if (begin>=begin2 && end<=end2)
        {
            ans=hb(ans,p[root]);
            return;
        }
        int mid=(begin+end)/2;
        chaxun(root*2,begin,mid,begin2,end2);chaxun(root*2+1,mid+1,end,begin2,end2);
    }
    int main()
    {
        scanf("%d%s%d",&n,s+1,&m);
        build(1,1,n);
        for (int i=1;i<=m;i++)
        {
            int op;
            op=read();
            if (op==1)
            {
                int a,b;
                a=read();b=read();gengxin(1,1,n,a,b);
            }
            else
            {
                long long l,r,a,k;
                l=read();r=read();ans.ans1=ans.ans2=ans.s1=ans.s2=ans.len=0;
                a=l/n*n;l-=a;r-=a;
                if (!l){l+=n;r+=n;}
                if (r<=n)chaxun(1,1,n,l,r);
                else
                {
                    k=(r-1)/n-(l-1)/n-1;
                    chaxun(1,1,n,l,n);
                    t[0]=p[1];
                    for (int i=0;i<=60;i++)
                    {
                        if (i)t[i]=hb(t[i-1],t[i-1]);
                        if ((1ll<<i)&k)ans=hb(ans,t[i]);
                    }
                    chaxun(1,1,n,1,(r%n!=0?r%n:n));
                }
                printf("%lld
    ",ans.ans1);
            }
        }
        return 0;
    }
  • 相关阅读:
    三比三:无线监控优点与传输技术剖解
    手把手教你学习FPGA系列视频教程_救护车鸣笛声
    世纪大争论:Linux还是GNU/Linux?
    [分享]我的LABVIEW快速开发串口测试软件实例
    高能效系统的功耗优化技术
    python学习小脚本多用户登录
    python学习三级菜单省市选择
    python学习购物车小程序
    python学习语句总结
    python学习猜年龄小游戏
  • 原文地址:https://www.cnblogs.com/1124828077ccj/p/12241944.html
Copyright © 2011-2022 走看看