博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
2019.01.04 bzoj2962: 序列操作(线段树+组合数学)
阅读量:4979 次
发布时间:2019-06-12

本文共 3202 字,大约阅读时间需要 10 分钟。

线段树基础题。
题意:要求维护区间区间中选择ccc个数相乘的所有方案的和(c≤20c\le20c20),支持区间加,区间取负。


由于c≤20c\le20c20,因此可以对于每个线段树节点可以暴力维护212121sumsumsum值,合并也很简单,是一个卷积的形式sumi=∑j=0isumjsumi−jsum_i=\sum_{j=0}^isum_jsum_{i-j}sumi=j=0isumjsumij可以用FFT优化一波(滑稽

区间取负并没有什么难度,对于sumisum_isumi来说,如果iii是偶数就并没有什么影响,如果iii是奇数把sumisum_isumi变成−sumi-sum_isumi即可。
关键在于区间加。
考虑到区间加对每个sumsumsum的影响,我们把a1a2...ana_1a_2...a_na1a2...an变成了(a1+x)(a2+x)...(an+x)(a_1+x)(a_2+x)...(a_n+x)(a1+x)(a2+x)...(an+x),我们设这个区间长度为lenlenlen,那么有组合数学的方法可以将这个式子展开:newsumi=∑j=0iClen−ji−jxjoldsumjnewsum_{i}=\sum_{j=0}^iC_{len-j}^{i-j}x^joldsum_jnewsumi=j=0iClenjijxjoldsumj 相当于是枚举每个括号里面xxx的个数来更新答案

然后就没啥了~~注意细节~~

代码:

#include
#define lc (p<<1)#define rc (p<<1|1)#define mid (T[p].l+T[p].r>>1)#define add(a,b) ((a)+(b)>=mod?(a)+(b)-mod:(a)+(b))#define mul(a,b) ((ll)(a)*(b)%mod)#define dec(a,b) ((a)>=(b)?(a)-(b):(a)-(b)+mod)#define ri register intusing namespace std;typedef long long ll;const int mod=19940417,N=5e5+5;int n,m,a[N],C[N][21];inline int read(){
int ans=0,w=1; char ch=getchar(); while(!isdigit(ch)){
if(ch=='-')w=-1;ch=getchar();} while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar(); return ans*w;}struct Node{
int l,r,sum[21],add;bool rev;Node(){
l=r=add=rev=0;for(ri i=0;i<=20;++i)sum[i]=0;}}T[N<<2];inline Node operator+(const Node&a,const Node&b){
Node ret; ret.l=a.l,ret.r=b.r; for(ri i=0;i<=20;++i)for(ri j=0;j<=i;++j)ret.sum[i]=add(ret.sum[i],mul(a.sum[j],b.sum[i-j])); return ret;}inline void pushadd(int p,int v){
T[p].add=add(T[p].add,v); for(ri i=min(T[p].r-T[p].l+1,20),len=T[p].r-T[p].l+1;~i;--i)for(ri j=i-1,mult=v;~j;--j,mult=mul(mult,v)) T[p].sum[i]=add(T[p].sum[i],mul(C[len-j][i-j],mul(mult,T[p].sum[j])));}inline void pushrev(int p){
T[p].rev^=1,T[p].add=dec(0,T[p].add); for(ri i=0;i<=20;++i)if(i&1)T[p].sum[i]=dec(0,T[p].sum[i]);}inline void pushdown(int p){
if(T[p].rev)pushrev(lc),pushrev(rc),T[p].rev^=1; if(T[p].add)pushadd(lc,T[p].add),pushadd(rc,T[p].add),T[p].add=0;}inline void build(int p,int l,int r){
T[p].l=l,T[p].r=r; if(T[p].l==T[p].r){
T[p].sum[0]=1,T[p].sum[1]=a[l];return;} build(lc,l,mid),build(rc,mid+1,r),T[p]=T[lc]+T[rc];}inline void update(int p,int ql,int qr,int v){
if(ql<=T[p].l&&T[p].r<=qr)return v?pushadd(p,v):pushrev(p); pushdown(p); if(qr<=mid)update(lc,ql,qr,v); else if(ql>mid)update(rc,ql,qr,v); else update(lc,ql,mid,v),update(rc,mid+1,qr,v); T[p]=T[lc]+T[rc];}inline Node query(int p,int ql,int qr){
if(ql<=T[p].l&&T[p].r<=qr)return T[p]; pushdown(p); if(qr<=mid)return query(lc,ql,qr); if(ql>mid)return query(rc,ql,qr); return query(lc,ql,mid)+query(rc,mid+1,qr);}inline void init(){
for(ri i=0;i<=n;++i)C[i][0]=1; for(ri i=1;i<=n;++i){
C[i][1]=i; for(ri j=2;j<=min(20,i);++j)C[i][j]=add(C[i-1][j],C[i-1][j-1]); } build(1,1,n);}int main(){
n=read(),m=read(); for(ri i=1;i<=n;++i)a[i]=(read()%mod+mod)%mod; init(); while(m--){
char s[2]; scanf("%s",s); int l=read(),r=read(),v; if(s[0]=='I'){
v=(read()%mod+mod)%mod; if(!v)continue; update(1,l,r,v); } else if(s[0]=='R')update(1,l,r,0); else cout<
<<'\n'; } return 0;}

转载于:https://www.cnblogs.com/ldxcaicai/p/10367782.html

你可能感兴趣的文章
hive安装以及hive on spark
查看>>
jz1074 【基础】寻找2的幂
查看>>
Wannafly模拟赛5 A 思维 D 暴力
查看>>
【Linux开发】CCS远程调试ARM,AM4378
查看>>
Linux之ssh服务介绍
查看>>
排序:冒泡排序
查看>>
Java中instanceof关键字的用法总结
查看>>
引用类型-Function类型
查看>>
(转)Android 仿订单出票效果 (附DEMO)
查看>>
数据库多张表导出到excel
查看>>
微信小程序去除button默认样式
查看>>
Where does Visual Studio look for C++ Header files?
查看>>
Java打包可执行jar包 包含外部文件
查看>>
Windows Phone开发(37):动画之ColorAnimation
查看>>
js中escape,encodeURI,encodeURIComponent 区别(转)
查看>>
sass学习笔记-安装
查看>>
Flask (二) cookie 与 session 模型
查看>>
修改添加网址的教程文件名
查看>>
[BZOJ 1017][JSOI2008]魔兽地图DotR(树形Dp)
查看>>
裁剪图片
查看>>