好题集 (14) - LG P4247 [清华集训 2012] 序列操作

题目传送门

题意:给定一序列,要求支持区间加、区间乘 \(-1\)、区间求选 \(c\) 个数相乘的方案之和,答案对 \(19940417\) 取模。\(n,m\le 5\times 10^4,|V|\le 10^9,c\le 20\)

神仙题。感觉并没有 SCOI2010 的同名题目难调?

序列操作先上线段树,考虑每个结点维护什么。

注意到 \(c\) 非常小,所以考虑在每个结点内维护 \(f_{0\sim 20}\),其中 \(f_i\) 表示从该结点对应的区间中选出 \(i\) 个数的答案。另外两个懒标记肯定是要有的,那么结点的信息确定了。

遵照 lxl 的指导,我们分别考虑标记对标记的影响、标记对信息的影响和信息间的合并。

标记对标记是容易的;加法标记不影响取反标记,取反标记使加法标记取反。

标记对信息的影响也是不难的。对于取反,直接将 \(f\) 的奇数项取反即可;下面讨论加法。

对于一个大小为 \(i\) 的下标子集 \(S\),整体加 \(x\) 后,其新的积为:

\[\prod\limits_{k\in S}(a_k+x)\tag{1} \]

这可以看作 \(k\) 个二项式的积,每个二项式可以贡献出前一项或后一项。枚举 \(T\subseteq S\) 表示贡献前一项的二项式,那么对于一个 \(T\),产生的乘积为:

\[\Big(\prod\limits_{k\in T} a_k\Big)x^{i-|T|}\tag{2} \]

\((1)(2)\) 整合起来,得到新的积:

\[\begin{align*} \prod\limits_{k\in S}(a_k+x)&=\prod\limits_{T\subseteq S}\Big(\prod\limits_{k\in T} a_k\Big)x^{i-|T|}\\ &=\sum\limits_{j=0}^i x^{i-j}\sum\limits_{|T|=j,T\subseteq S}\prod\limits_{k\in T}a_k\tag{3} \end{align*} \]

\(S\) 看作一个被加法区间完全覆盖,且大小为 \(i\) 的下标集合。那么新的 \(f\) 就是:

\[f_{\text{new}_i}=\sum\limits_{|S|=i}\sum\limits_{j=0}^i x^{i-j}\sum\limits_{|T|=j,T\subseteq S}\prod\limits_{k\in T}a_k \]

设区间长为 \(L\)。交换求和顺序,先固定大小为 \(j\)\(T\),再考虑哪些 \(S\) 包含 \(T\) 且大小为 \(i\)。每个这样的 \(T\) 的出现次数就是包含 \(T\)\(i\) 元子集 \(S\) 的个数,从剩下的 \((L-j)\) 个位置中选出 \((i-j)\) 个即可,也就是 \({L-j}\choose{i-j}\)。所有 \(j\) 元子集 \(T\) 的积之和就是 \(f_{\text{old}_j}\),所以得到:

\[f_{\text{new}_i}=\sum\limits_{j=0}^i x^{i-j}\cdot f_{\text{old}_j}\cdot {{L-j}\choose{i-j}} \]

然后 \(O(c_{\max}^2)\) 合并,这部分就搞完了。

最后考虑信息间的合并。容易发现就是把左右儿子的 \(f\) 做一个卷积,也就是:

\[f_{u,i}=\sum\limits_{j=0}^i f_{\text{ls},j}\cdot f_{\text{rs},i-j} \]

然后也就没了。总复杂度 \(O(c_{\max}^2 n\log n)\)

#ifndef ONLINE_JUDGE
#pragma GCC optimize("O3,Ofast,unroll-loops")
#endif
#pragma GCC target("sse,sse2,sse3,ssse3,sse4,popcnt,abm,mmx,avx,avx2,tune=native")
#include<iostream>
using namespace std;

const int N=5e4+5;

int n,m;
int a[N];

namespace OIfast{
    
    char buf[1<<21],*p1,*p2,*top,buffer[1<<21];
    #define getchar()(p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?0:*p1++)
    #define gc getchar()
    
    inline int read(){
        static int n,f;n=0,f=1;static char c(gc);
        while(!isdigit(c)){if(c=='-')f=-1;c=gc;}
        while(isdigit(c))n=(n<<3)+(n<<1)+(c^48),c=gc;
        return n*f;
    }
    
}using namespace OIfast;

namespace KeQing_Forever{
    
    const int p=19940417;
    
    inline int mod(int x){return (x+p)%p;}
    inline int mul(int a,int b){return 1LL*a*b%p;}
    inline void mult(int &a,int b){return a=mul(a,b),void();}
    inline int add(int a,int b){return mod(a+b);}
    inline void adt(int &a,int b){return a=add(a,b),void();}
    inline int qpow(int a,int b){int res=1;while(b){if(b&1)mult(res,a);mult(a,a),b>>=1;}return res;}
    
    int C[N][25];
    
    inline void init(){
        for(int i=0;i<=n;++i){
            C[i][0]=1;
            for(int j=1;j<=i&&j<=20;++j){
                C[i][j]=add(C[i-1][j-1],C[i-1][j]);
            }
        }
        return ;
    }
    
}using namespace KeQing_Forever;

namespace SGT{
    
    #define ls u<<1
    #define rs u<<1|1
    #define mid ((L+R)>>1)
    
    struct node{
        int la;
        bool flg;
        int f[25];
    }t[N<<2];
    
    node gunmu;
    
    inline node merge(node a,node b){
        node res=gunmu;
        for(int i=1;i<=20;++i){
            res.f[i]=0;
            for(int j=0;j<=i;++j)adt(res.f[i],mul(a.f[j],b.f[i-j]));
        }
        return res;
    }
    
    inline void pushup(int u){
        for(int i=1;i<=20;++i){
            t[u].f[i]=0;
            for(int j=0;j<=i;++j)adt(t[u].f[i],mul(t[ls].f[j],t[rs].f[i-j]));
        }
        return ;
    }
    
    int tmp[25];
    
    inline void mtg_add(int u,int v,int L,int R){
        for(int i=0;i<=20;++i)tmp[i]=t[u].f[i];
        for(int i=1;i<=20;++i){
            t[u].f[i]=0;
            for(int j=0;j<=i;++j)adt(t[u].f[i],mul(qpow(v,i-j),mul(tmp[j],C[R-L+1-j][i-j])));
        }
        return adt(t[u].la,v),void();
    }
    
    inline void mtg_rev(int u){
        for(int i=1;i<=20;i+=2)t[u].f[i]=mod(-t[u].f[i]);
        return t[u].flg^=1,t[u].la=mod(-t[u].la),void();
    }
    
    inline void pushdown(int u,int L,int R){
        if(t[u].flg)mtg_rev(ls),mtg_rev(rs);
        if(t[u].la)mtg_add(ls,t[u].la,L,mid),mtg_add(rs,t[u].la,mid+1,R);
        return t[u].la=t[u].flg=0,void();
    }
    
    inline void build(int u,int L,int R){
        t[u].f[0]=1;
        if(L==R)return t[u].f[1]=mod(a[L]),void();
        return build(ls,L,mid),build(rs,mid+1,R),pushup(u),void();
    }
    
    inline void upd_add(int u,int l,int r,int v,int L,int R){
        if(l>R||L>r)return ;
        if(l<=L&&R<=r)return mtg_add(u,v,L,R),void();
        return pushdown(u,L,R),upd_add(ls,l,r,v,L,mid),upd_add(rs,l,r,v,mid+1,R),pushup(u),void();
    }
    
    inline void upd_rev(int u,int l,int r,int L,int R){
        if(l>R||L>r)return ;
        if(l<=L&&R<=r)return mtg_rev(u),void();
        return pushdown(u,L,R),upd_rev(ls,l,r,L,mid),upd_rev(rs,l,r,mid+1,R),pushup(u),void();
    }
    
    inline void qry(int u,node &res,int l,int r,int L,int R){
        if(l>R||L>r)return ;
        if(l<=L&&R<=r)return res=merge(res,t[u]),void();
        return pushdown(u,L,R),qry(ls,res,l,r,L,mid),qry(rs,res,l,r,mid+1,R),void();
    }
    
    #undef ls
    #undef rs
    #undef mid
    
}using namespace SGT;

inline void work(){
    char op=gc;while(!isalpha(op))op=gc;
    if(1==2){
        puts("wow");
    }else if(op=='I'){
        int l=read(),r=read(),x=mod(read());
        upd_add(1,l,r,x,1,n);
    }else if(op=='R'){
        int l=read(),r=read();
        upd_rev(1,l,r,1,n);
    }else if(op=='Q'){
        int l=read(),r=read(),c=read();
        node tmp=gunmu;qry(1,tmp,l,r,1,n);
        printf("%d\n",tmp.f[c]);
    }
    return ;
}

signed main(){
    n=read(),m=read();init();
    for(int i=1;i<=n;++i)a[i]=mod(read());
    gunmu.f[0]=1;
    build(1,1,n);while(m--)work();
    return 0;
}

提交记录

posted @ 2026-06-26 21:54  DX3906_ourstar  阅读(5)  评论(0)    收藏  举报