Luogu P4247 [清华集训2012]序列操作
题意
给定一个长度为 \(n\) 的序列 \(a\) 和 \(q\) 次操作,每次操作形如以下三种:
I a b c,表示将 \([a,b]\) 内的元素加 \(c\)。R a b,表示将 \([a,b]\) 内的元素变成相反数。Q a b c,表示在 \([a,b]\) 内所有选出 \(c\) 个元素的乘积之和。
对于每一个询问操作,输出答案对 \(19940417\) 取模的值。
\(\texttt{Data Range:}1\leq n\leq q\leq 50000\)
题解
好题啊。
看到这种题马上想到用线段树维护区间内 \((1+a_ix)\) 的乘积,然后答案就是取一项。
考虑如何打懒标记。对于相反数的话,设 \(F(x)=\prod\limits_{i=1}^{n}(1+a_ix)\),那么有
\]
这个结论大概可以手玩一下,所以说打懒标记的时候只需要奇次项取相反数即可。
接下来是区间加这个大毒瘤,还是考虑懒标记的打法。
接下来为了方便我们用 \(S_k\) 表示 \(a_1,a_2,\cdots a_n\) 中取 \(k\) 项的所有乘积之和,那么有
\]
注意到我们可以枚举一下多项式的 \(i\) 次项系数和这一项系数里面是取 \(j\) 项的所有方案数的乘积之和,那么我们得到当前枚举的 \(i,j\) 对应的 \(S_j\) 的系数为:
\]
这里有一个组合意义的解释:首先将 \((a_i+c)x\) 看做整体,从 \(n\) 个中选出 \(i\) 个构成 \((a_1+c)(a_2+c)\cdots(a_i+c)x^i\) 这一项。接下来在求出这一项中对应的 \(c^{i-j}\) 的系数,也就是选了 \(j\) 个 \(a\) 和 \(i-j\) 个 \(c\)。最后,一共有 \(\binom{n}{j}\) 种方式从这些 \(a_i\) 中出选 \(j\) 个,而每种方式被计算的次数都是相等的,于是得除掉,就得到这个东西被算了几次,也就是 \(S_j\) 的系数。
利用一些基本的恒等式我们有
\]
于是枚举一下这个东西就没了,时间复杂度 \(O(c^2n\log n)\)。
代码
#include<bits/stdc++.h>
using namespace std;
typedef int ll;
typedef long long int li;
const ll MAXN=5e4+51,MOD=19940417;
struct SegmentTree{
ll l,r,tag,tag2;
ll f[21];
};
SegmentTree tree[MAXN<<2];
ll n,qcnt,l,r,u;
char op;
ll x[MAXN],pw[MAXN],binom[MAXN][21],g[21];
inline ll read()
{
register ll num=0,neg=1;
register char ch=getchar();
while(!isdigit(ch)&&ch!='-')
{
ch=getchar();
}
if(ch=='-')
{
neg=-1;
ch=getchar();
}
while(isdigit(ch))
{
num=(num<<3)+(num<<1)+(ch-'0');
ch=getchar();
}
return num*neg;
}
inline void conv(ll *f,ll *g,ll *res)
{
li cur;
for(register int i=0;i<=20;i++)
{
cur=0;
for(register int j=0;j<=i;j++)
{
cur+=(li)f[j]*g[i-j]%MOD;
}
res[i]=cur%MOD;
}
}
#define ls node<<1
#define rs (node<<1)|1
inline void update(ll node)
{
conv(tree[ls].f,tree[rs].f,tree[node].f);
}
inline void create(ll l,ll r,ll node)
{
tree[node]=(SegmentTree){l,r,0,1,{1}};
if(l==r)
{
return (void)(tree[node].f[1]=x[l]);
}
ll mid=(l+r)>>1;
create(l,mid,ls),create(mid+1,r,rs),update(node);
}
inline void spread(ll node)
{
if(tree[node].tag2!=1)
{
for(register int i=1;i<=20;i+=2)
{
tree[ls].f[i]=(MOD-tree[ls].f[i])%MOD;
tree[rs].f[i]=(MOD-tree[rs].f[i])%MOD;
}
tree[ls].tag2*=-1,tree[rs].tag2*=-1,tree[node].tag2=1;
tree[ls].tag=(MOD-tree[ls].tag)%MOD;
tree[rs].tag=(MOD-tree[rs].tag)%MOD;
}
if(tree[node].tag)
{
ll lenl=tree[ls].r-tree[ls].l+1,lenr=tree[rs].r-tree[rs].l+1;
li curl,curr;
for(register int i=1;i<=20;i++)
{
pw[i]=(li)pw[i-1]*tree[node].tag%MOD;
}
for(register int i=20;i;i--)
{
curl=curr=0;
for(register int j=0;j<i;j++)
{
curl+=(li)tree[ls].f[j]*pw[i-j]%MOD*binom[lenl-j][i-j]%MOD;
curr+=(li)tree[rs].f[j]*pw[i-j]%MOD*binom[lenr-j][i-j]%MOD;
}
tree[ls].f[i]=(tree[ls].f[i]+curl)%MOD;
tree[rs].f[i]=(tree[rs].f[i]+curr)%MOD;
}
tree[ls].tag+=tree[node].tag,tree[rs].tag+=tree[node].tag;
tree[ls].tag%=MOD,tree[rs].tag%=MOD,tree[node].tag=0;
}
}
inline void add(ll l,ll r,ll val,ll node)
{
if(l<=tree[node].l&&r>=tree[node].r)
{
ll len=tree[node].r-tree[node].l+1;
li cur=0;
for(register int i=1;i<=20;i++)
{
pw[i]=(li)pw[i-1]*val%MOD;
}
for(register int i=20;i;i--)
{
cur=0;
for(register int j=0;j<i;j++)
{
cur+=(li)tree[node].f[j]*pw[i-j]%MOD*binom[len-j][i-j]%MOD;
}
tree[node].f[i]=(tree[node].f[i]+cur)%MOD;
}
return (void)(tree[node].tag=(tree[node].tag+val)%MOD);
}
ll mid=(tree[node].l+tree[node].r)>>1;
spread(node);
l<=mid?add(l,r,val,ls):(void)1,r>mid?add(l,r,val,rs):(void)1;
update(node);
}
inline void mul(ll l,ll r,ll node)
{
if(l<=tree[node].l&&r>=tree[node].r)
{
for(register int i=1;i<=20;i+=2)
{
tree[node].f[i]=(MOD-tree[node].f[i])%MOD;
}
tree[node].tag=(MOD-tree[node].tag)%MOD;
return (void)(tree[node].tag2*=-1);
}
ll mid=(tree[node].l+tree[node].r)>>1;
spread(node);
l<=mid?mul(l,r,ls):(void)1,r>mid?mul(l,r,rs):(void)1,update(node);
}
inline SegmentTree query(ll l,ll r,ll node)
{
SegmentTree res;
if(l<=tree[node].l&&r>=tree[node].r)
{
return tree[node];
}
ll mid=(tree[node].l+tree[node].r)>>1;
spread(node),conv(l<=mid?query(l,r,ls).f:g,r>mid?query(l,r,rs).f:g,res.f);
return res;
}
int main()
{
n=read(),qcnt=read(),binom[0][0]=pw[0]=g[0]=1;
for(register int i=1;i<=n;i++)
{
x[i]=(read()%MOD+MOD)%MOD;
}
for(register int i=1;i<=n;i++)
{
binom[i][0]=1;
for(register int j=1;j<=20;j++)
{
binom[i][j]=(binom[i-1][j]+binom[i-1][j-1])%MOD;
}
}
create(1,n,1);
for(register int i=0;i<qcnt;i++)
{
cin>>op,l=read(),r=read();
if(op=='I')
{
u=(read()%MOD+MOD)%MOD,add(l,r,u,1);
}
if(op=='R')
{
mul(l,r,1);
}
if(op=='Q')
{
u=read();
printf("%d\n",query(l,r,1).f[u]);
}
}
}
Luogu P4247 [清华集训2012]序列操作的更多相关文章
- 【题解】P4247 [清华集训]序列操作(线段树修改DP)
[题解]P4247 [清华集训]序列操作(线段树修改DP) 一道神仙数据结构(DP)题. 题目大意 给定你一个序列,会区间加和区间变相反数,要你支持查询一段区间内任意选择\(c\)个数乘起来的和.对1 ...
- P2260 [清华集训2012]模积和
P2260 [清华集训2012]模积和 整除分块+逆元 详细题解移步P2260题解板块 式子可以拆开分别求解,具体见题解 这里主要讲的是整除分块(数论分块)和mod不为素数时如何求逆元 整除分块:求Σ ...
- P2260 [清华集训2012]模积和 【整除分块】
一.题目 P2260 [清华集训2012]模积和 二.分析 参考文章:click here 具体的公式推导可以看参考文章.博主的证明很详细. 自己在写的时候问题不在公式推导,公式还是能够比较顺利的推导 ...
- 洛谷 P2260 [清华集训2012]模积和 || bzoj2956
https://www.lydsy.com/JudgeOnline/problem.php?id=2956 https://www.luogu.org/problemnew/show/P2260 暴力 ...
- 洛谷P2260 [清华集训2012]模积和(容斥+数论分块)
题意 https://www.luogu.com.cn/problem/P2260 思路 具体思路见下图: 注意这个模数不是质数,不能用快速幂来求逆元,要用扩展gcd. 代码 #include< ...
- 【luogu P4007 清华集训2017】小Y和恐怖奴隶主
题目背景 “A fight? Count me in!” 要打架了,算我一个. “Everyone, get in here!” 所有人,都过来! 题目描述 小 Y 是一个喜欢玩游戏的 OIer.一天 ...
- 【luogu P4005 清华集训2017】小Y和地铁
题目描述 小 Y 是一个爱好旅行的 OIer.一天,她来到了一个新的城市.由于不熟悉那里的交通系统,她选择了坐地铁. 她发现每条地铁线路可以看成平面上的一条曲线,不同线路的交点处一定会设有 换乘站 . ...
- BSOJ 4062 -- 【清华集训2012】串珠子
Description 铭铭有n个十分漂亮的珠子和若干根颜色不同的绳子.现在铭铭想用绳子把所有的珠子连接成一个整体. 现在已知所有珠子互不相同,用整数1到n编号.对于第i个珠子和第j个珠子,可以选择不 ...
- luoguP2260 [清华集训2012]模积和
题意 \(\sum\limits_{i=1}^{n}\sum\limits_{j=1}^{m}n\%i*m\%j*[i!=j]\) \(\sum\limits_{i=1}^{n}\sum\limits ...
随机推荐
- VS2017 Xamarin开发Android时首次部署完成后直接闪退
项目属性切换到Android选项,在打包属性上有一个[使用共享运行时]的选项要取消勾选,默认打钩时apk文件比较小,但程序无法运行起来. 取消后安装包一小变成几十M,这个目前好像没什么好的解决办法,毕 ...
- Python-信号量和线程池-semaphore ThreadPollExector
信号量 其实本质上是锁,Lock是单锁,信号量是指定多把锁,也就是说通过信号量指定多个数线程可以访问相同资源,一般情况下读操作可以有多个,但写操作同时只有一个 信号量模块 semaphore # 使用 ...
- Centos-当前和过去登入系统用户信息-last
last 获取当前和过去登入系统的用户相关信息,执行last指令的时候会默认读取/var/log/wtmp文件 相关参数 -a 把客户端IP显示到最后一列 -R 不显示客户端IP地址或主机名 -n 显 ...
- BeautifulSoup使用手册(查询篇)
目录 开始使用呢 解析器 四种对象 tag对象 标签名(name) 属性值(Attributes) 多值属性 内容 Comment对象 prettify()方法 find_all方法 contents ...
- 【题解】CF1228D Complete Tripartite
Link 题目大意:给定一个无向图,将它划分为三个点集,要求在一个点集中的点没有边相连,且颜色相同,不同集合中的点互相有边相连. \(\text{Solution:}\) 我们发现,与一个点之间没有边 ...
- OpenCV图像加载与保存
OpenCV中的图像加载与保存 头文件是包含的库,在GitHub上下载的 imread("图片路径",图片加载方式) 图片加载方式: IMREAD_GRAYSCALE 灰度图像 I ...
- 编程体系结构(06):Java面向对象
本文源码:GitHub·点这里 || GitEE·点这里 一.基础概念 1.面向对象概念 面向对象编程的主要思想是把构成问题的各个事务分解成各个对象,建立对象的目的不是为了完成一个步骤,而是为了描叙一 ...
- MLHPC 2018 | Aluminum: An Asynchronous, GPU-Aware Communication Library Optimized for Large-Scale Training of Deep Neural Networks on HPC Systems
这篇文章主要介绍了一个名为Aluminum通信库,在这个库中主要针对Allreduce做了一些关于计算通信重叠以及针对延迟的优化,以加速分布式深度学习训练过程. 分布式训练的通信需求 通信何时发生 一 ...
- SQL Server查询优化指南
1.尽量不要使用is null,否则将导致引擎放弃使用索引而进行全表扫描.2.char是固定长度,速度快,但占空间,varchar不固定长度,不占空间,但速度慢.3.能使用数字类型就不要使用字符,查询 ...
- Go语言中的常见的几个坑
目录 1.for range 2.defer与闭包 3.map内存溢出 4.协程泄漏 5.http手动关闭 记录一下日常中遇到的几个坑,加深一下印象. 1.for range 这个是比较常见的问题了, ...