好题集 (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\) 后,其新的积为:
这可以看作 \(k\) 个二项式的积,每个二项式可以贡献出前一项或后一项。枚举 \(T\subseteq S\) 表示贡献前一项的二项式,那么对于一个 \(T\),产生的乘积为:
把 \((1)(2)\) 整合起来,得到新的积:
将 \(S\) 看作一个被加法区间完全覆盖,且大小为 \(i\) 的下标集合。那么新的 \(f\) 就是:
设区间长为 \(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}\),所以得到:
然后 \(O(c_{\max}^2)\) 合并,这部分就搞完了。
最后考虑信息间的合并。容易发现就是把左右儿子的 \(f\) 做一个卷积,也就是:
然后也就没了。总复杂度 \(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;
}
提交记录。

浙公网安备 33010602011771号