• 暑假集训单切赛第一场 CF 266E More Queries to Array(线段树+二项式展开式)


    比赛时,第二题就是做的这个,当时果断没仔细考虑,直接用线段树暴力求。结果易想而知,超时了。

    比赛后搜了搜题解,恍然大悟。

    思路:显然用线段树,但是由于每次查询都会有变,所以不可能存储题目中的式子。
       这里要注意:k的值非常小,所以应该是将式子按二项式定理展开
       (i-L+1)^k=(i+(1-L))^k
       展开之后可以发现:我们可以在节点存储ai*i,ai*i^2,ai*i^3,ai*i^4,ai*i^5 (L<=i<=R)的累加和。
       至于关于(1-L)^j(j=0~5)可以预先枚举所有的L,预先处理一下用数组存储。
       展开式要用到组合,所以组合也要预先处理一下。
      
       当更新时,我们发现l<=i<=r区间中所有的ai都变为x,
       累加和分别为x*(L+...+R),x*(L^2+...+R^2),x*(L^3+...+R^3),...,x*(L^5+...+R^5)
       因此我们也要预先处理1^j+2^j+...+n^j的和,存到一个数组中去

    #include <iostream>
    #include <algorithm>
    #include <stdio.h>
    #include <string.h>
    #include <queue>
    
    using namespace std;
    const long long mod=1000000007;
    const int maxn=4*100010;
    const int maxnN=100005;
    int n,m,k;
    int L,R;
    long long ans;
    int C[6][6];
    long long S[maxnN][6];    //S[i][j]存储(1-i)^j的值
    long long LMi[maxnN][6];  //LMi[i][j]存储i^j的值,1<=i<=n,即ai*i^j中的i^j
    long long sum[maxnN][6];  //sum[i][j] 表示1^j+2^j……+i^j的值
    struct Node {
        int left,right;
        long long pow0,pow1,pow2,pow3,pow4,pow5;   //powj: ai*i^j的和,j=0~5
        bool lazy;
        int add;
    } tree[maxn];
    
    void init1() {
        C[0][0]=1;
        for(int i=1; i<=5; i++) {
            C[i][0]=1;
            C[i][i]=1;
            for(int j=1; j<i; j++) {
                C[i][j]=C[i-1][j-1]+C[i-1][j];  
            }
        }
    }
    
    void init2() {
        memset(sum,0,sizeof(sum));
        for(int i=1; i<=n; i++) {
            S[i][0]=1;
            LMi[i][0]=1;
            sum[i][0]=i;
            for(int j=1; j<=5; j++) {
                LMi[i][j]=(LMi[i][j-1]*i)%mod;
                S[i][j]=(S[i][j-1]*(1-i)%mod+mod)%mod;
                sum[i][j]=(sum[i-1][j]+LMi[i][j])%mod;
            }
        }
    }
    
    void pushUp(int rt) {
        tree[rt].pow0=(tree[rt<<1].pow0+tree[rt<<1|1].pow0)%mod;
        tree[rt].pow1=(tree[rt<<1].pow1+tree[rt<<1|1].pow1)%mod;
        tree[rt].pow2=(tree[rt<<1].pow2+tree[rt<<1|1].pow2)%mod;
        tree[rt].pow3=(tree[rt<<1].pow3+tree[rt<<1|1].pow3)%mod;
        tree[rt].pow4=(tree[rt<<1].pow4+tree[rt<<1|1].pow4)%mod;
        tree[rt].pow5=(tree[rt<<1].pow5+tree[rt<<1|1].pow5)%mod;
    }
    
    void build(int left,int right,int rt) {
        tree[rt].left=left;
        tree[rt].right=right;
        tree[rt].lazy=false;
        tree[rt].add=0;
        if(left==right) {
            scanf("%I64d",&tree[rt].pow0);
            tree[rt].pow1=(tree[rt].pow0*LMi[left][1])%mod;
            tree[rt].pow2=(tree[rt].pow0*LMi[left][2])%mod;
            tree[rt].pow3=(tree[rt].pow0*LMi[left][3])%mod;
            tree[rt].pow4=(tree[rt].pow0*LMi[left][4])%mod;
            tree[rt].pow5=(tree[rt].pow0*LMi[left][5])%mod;
            return;
        }
        int mid=(left+right)>>1;
        build(left,mid,rt<<1);
        build(mid+1,right,rt<<1|1);
        pushUp(rt);
    }
    
    void pushDown(int rt);
    void update(int l,int r,int value,int rt) {
        if(l==tree[rt].left && tree[rt].right==r) {
            tree[rt].lazy=true;
            tree[rt].add=value;
            tree[rt].pow0=value*(((sum[r][0]-sum[l-1][0])%mod+mod)%mod);
            tree[rt].pow1=value*(((sum[r][1]-sum[l-1][1])%mod+mod)%mod);
            tree[rt].pow2=value*(((sum[r][2]-sum[l-1][2])%mod+mod)%mod);
            tree[rt].pow3=value*(((sum[r][3]-sum[l-1][3])%mod+mod)%mod);
            tree[rt].pow4=value*(((sum[r][4]-sum[l-1][4])%mod+mod)%mod);
            tree[rt].pow5=value*(((sum[r][5]-sum[l-1][5])%mod+mod)%mod);
            return;    
        }
        pushDown(rt);
    
        int mid=(tree[rt].left+tree[rt].right)>>1;
        if(r<=mid) {
            update(l,r,value,rt<<1);
        } else if(l>mid) {
            update(l,r,value,rt<<1|1);
        } else {
            update(l,mid,value,rt<<1);
            update(mid+1,r,value,rt<<1|1);
        }
        pushUp(rt);
    
    }
    
    void pushDown(int rt) {
        if(tree[rt].lazy && tree[rt].left!=tree[rt].right) {
            tree[rt<<1].lazy=tree[rt<<1|1].lazy=true;
            long long tmp=tree[rt].add;
    
            tree[rt<<1].add=tree[rt].add;
            tree[rt<<1|1].add=tree[rt].add;
    
            int mid=(tree[rt].left+tree[rt].right)>>1;
            //这里可以直接调用update方法对儿子进行更新
            update(tree[rt].left,mid,tmp,rt<<1);
            update(mid+1,tree[rt].right,tmp,rt<<1|1);  
    
            tree[rt].add=0;
            tree[rt].lazy=false;
        }
    }
    
    
    
    long long query(int l,int r,int rt,int i) {
        if(l==tree[rt].left && tree[rt].right==r) {
            if(i==0)
                return tree[rt].pow0;
            else if(i==1)
                return tree[rt].pow1;
            else if(i==2)
                return tree[rt].pow2;
            else if(i==3)
                return tree[rt].pow3;
            else if(i==4)
                return tree[rt].pow4;
            else if(i==5)
                return tree[rt].pow5;
        }
        pushDown(rt);
    
        int mid=(tree[rt].left+tree[rt].right)>>1;
        if(r<=mid) {
            return query(l,r,rt<<1,i)%mod;
        } else if(l>mid) {
            return query(l,r,rt<<1|1,i)%mod;
        } else {
            return (query(l,mid,rt<<1,i)+query(mid+1,r,rt<<1|1,i))%mod;
        }
    }
    
    int main() {
        int x;
        char ch[5];
    
        scanf("%d%d",&n,&m);
        init1();
        init2();
    
        build(1,n,1);
        for(int i=1; i<=m; i++) {
            scanf("%s",ch);
            if(ch[0]=='=') {
                scanf("%d%d%d",&L,&R,&x);
                update(L,R,x,1);
            } else {
                scanf("%d%d%d",&L,&R,&k);
                ans=0;
    
                //for(int i=0;i<=k;i++){
                for(int i=k; i>=0; i--) {
                    //ans=((ans+((query(L,R,1,i)*C[k][i]%mod)*S[L][k-i]%mod))%mod+mod)%mod;
                    ans=(ans+((query(L,R,1,i)*C[k][i]%mod)*S[L][k-i]%mod))%mod;
    
                }
    
                printf("%I64d
    ",ans);
            }
        }
        return 0;
    }
  • 相关阅读:
    python入门:字符编码
    python入门:字符串2
    使用keepalived实现高可用
    基于sersync实现实时同步
    kubeadm 的工作原理
    docker-stop不能停止容器
    kubernetes 中的证书工作机制
    docker-hub中python的tag都代表什么意思
    MFS 介绍
    安装sngrep线路抓包工具
  • 原文地址:https://www.cnblogs.com/chenxiwenruo/p/3285535.html
Copyright © 2020-2023  润新知