【题解】P4247 [清华集训]序列操作(线段树修改DP)
【题解】P4247 [清华集训]序列操作(线段树修改DP)
一道神仙数据结构(DP)题。
题目大意
给定你一个序列,会区间加和区间变相反数,要你支持查询一段区间内任意选择\(c\)个数乘起来的和。对19940417取膜。
咋做
我们这一类题看来有一个套路就是用线段树维护一个DP数组,然后线段树节点合并就用一点组合的技巧..
设\(dp(i)\)表示在该区间里选择\(i\)个乘起来的和,考虑如何合并区间,很简单就是
\]
先考虑加法怎么办,可以这样考虑,每个数加上一个\(\Delta x\) 相当于从\((a)(b)(c)\)变成\((a+\Delta x)(b+\Delta x)(\Delta c+x)\),把式子拆一下就是变成
\]
观察一下括号里面的东西,发现就是\(dp(?)\),就是随意选取\(?\)个的和,还要乘上一个组合数。所以可以直接在\(dp\)数组里更新。
\]
再阐释一下这个式子的组合意义,拆上面那个括号,可以这样看,每次贡献都是从左往右每个括号里,我可以随意选择一个字母或者\(\Delta x\)贡献一下,一次选择了\(k\)个\(\Delta x\)的贡献就是不同选择字母情况的\((\Delta x)^k\times (\underbrace {ab\dots z}_{len-k\text{个}})\) 。的和,而我们之前维护的\(dp(len-k)\)就可以用了。又因为一个\(dp(i)\)数组里不一定只有\((a)(b)(c)\),可能还会有\((\alpha)(\beta)(\theta)\),所以还要一个组合数。
再考虑取反怎么办,显然就是\(dp(\text{奇数})\)取反就好了。顺便把lazytag取反。
代码
//@winlere
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define lef l,mid,pos<<1
#define rgt mid+1,r,pos<<1|1
#define all 1,n,1
#define midd register int mid=(l+r)>>1
using namespace std; typedef long long ll; typedef const int& ct;
inline int qr(){
register int ret=0,f=0;
register char c=getchar();
while(c<48||c>57)f|=c==45,c=getchar();
while(c>=48&&c<=57) ret=ret*10+c-48,c=getchar();
return f?-ret:ret;
}
const int maxn=5e4+1;
const int mod=19940417;
int add[maxn<<2|1];
int anti[maxn<<2|1];
int c[maxn][21];
int temp[21];
struct DP{
int dp[21];
DP(){memset(dp,0,sizeof dp);dp[0]=1;}
inline void debug(){
puts("Debug=");
for(register int t=1;t<=20;++t)
printf("%d ",dp[t]);
putchar('\n');
}
inline int& operator[](int x){return dp[x];}
inline void upd(DP&a,DP&b){
for(register int t=1;t<=20;++t) dp[t]=0;
dp[0]=1;
for(register int t=1;t<=20;++t)
for(register int i=0;i<=t;++i)
dp[t]=(dp[t]+1ll*a[i]*b[t-i]%mod)%mod;
}
inline void upd(DP a){
for(register int t=0;t<=20;++t) temp[t]=0;
temp[0]=1;
int*dp1=a.dp;
for(register int t=1;t<=20;++t)
for(register int i=0;i<=t;++i)
temp[t]=(temp[t]+1ll*dp[i]*dp1[t-i]%mod)%mod;
for(register int t=0;t<=20;++t)
dp[t]=temp[t];
}
}data[maxn<<2];
inline void pushup(const int&pos){
data[pos].upd(data[pos<<1],data[pos<<1|1]);
}
inline void getadd(const int&pos,const int&AD,const int&l,const int&r){
int* dp=data[pos].dp;
for(register int t=min(r-l+1,20),w,t1;t;--t){
w=1;t1=0;
for(register int i=0;i<=t;++i,w=1ll*w*AD%mod)
t1=(t1+1ll*dp[t-i]*c[r-l+1-t+i][i]%mod*1ll*w%mod);
dp[t]=t1;
}
}
inline void getanti(const int&pos){
int*dp=data[pos].dp;
for(register int t=1;t<=20;t+=2)
dp[t]=(mod-dp[t]%mod)%mod;
}
inline void pushdown(const int&pos,const int&l,const int&mid,const int&r){
if(anti[pos]){
anti[pos<<1]^=1;anti[pos<<1|1]^=1;
getanti(pos<<1);getanti(pos<<1|1);
add[pos<<1]=(mod-add[pos<<1]%mod)%mod;
add[pos<<1|1]=(mod-add[pos<<1|1]%mod)%mod;
anti[pos]=0;
}
if(add[pos]){
getadd(pos<<1,add[pos],l,mid);
getadd(pos<<1|1,add[pos],mid+1,r);
add[pos<<1]=(add[pos<<1]+add[pos]%mod)%mod;
add[pos<<1|1]=(add[pos<<1|1]+add[pos]%mod)%mod;
add[pos]=0;
}
}
void build(ct l,ct r,ct pos){midd;
if(l==r){data[pos][1]=(qr()%mod+mod)%mod;return;}
build(lef);build(rgt);
pushup(pos);
}
DP RET;
void que(ct L,ct R,ct l,ct r,ct pos){
if(L>r||R<l)return;
if(L<=l&&r<=R){RET.upd(data[pos]);return;}
midd;pushdown(pos,l,mid,r);
que(L,R,lef),que(L,R,rgt);
}
void upd(ct L,ct R,ct k,ct l,ct r,ct pos){
if(L>r||R<l)return;
if(L<=l&&r<=R){
add[pos]=(add[pos]+k)%mod;
getadd(pos,k,l,r);
return;
}midd;
pushdown(pos,l,mid,r);
upd(L,R,k,lef);upd(L,R,k,rgt);
pushup(pos);
}
void upd(ct L,ct R,ct l,ct r,ct pos){
if(L>r||R<l)return;
if(L<=l&&r<=R){
anti[pos]^=1;
getanti(pos);
add[pos]=(mod-add[pos])%mod;
return;
}midd;
pushdown(pos,l,mid,r);
upd(L,R,lef);upd(L,R,rgt);
pushup(pos);
}
inline char cinchar(){
register char c=getchar();
while(c!='I'&&c!='R'&&c!='Q') c=getchar();
return c;
}
int main(){
for(register int t=0;t<maxn;++t) c[t][0]=1;
for(register int t=1;t<maxn;++t)
for(register int i=1;i<=20;++i)
c[t][i]=(c[t-1][i-1]+c[t-1][i])%mod;
int n=qr(),q=qr();
build(all);
for(register int t=1,t1,t2,t3;t<=q;++t){
register char c=cinchar();
if(c=='I'){
t1=qr();t2=qr();t3=(qr()%mod+mod)%mod;
upd(t1,t2,t3,all);
}
if(c=='R'){
t1=qr();t2=qr();
upd(t1,t2,all);
}
if(c=='Q'){
t1=qr(),t2=qr();t3=qr();
RET=::DP();
que(t1,t2,all);
printf("%d\n",RET[t3]);
}
}
return 0;
}
【题解】P4247 [清华集训]序列操作(线段树修改DP)的更多相关文章
- 2018.07.08 hdu4521 小明系列问题——小明序列(线段树+简单dp)
小明系列问题--小明序列 Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 65535/32768 K (Java/Others) Proble ...
- 4.11 省选模拟赛 序列 二分 线段树优化dp set优化dp 缩点
容易想到二分. 看到第一个条件容易想到缩点. 第二个条件自然是分段 然后让总和最小 容易想到dp. 缩点为先:我是采用了取了一个前缀最小值数组 二分+并查集缩点 当然也是可以直接采用 其他的奇奇怪怪的 ...
- 【BZOJ-2962】序列操作 线段树 + 区间卷积
2962: 序列操作 Time Limit: 50 Sec Memory Limit: 256 MBSubmit: 678 Solved: 246[Submit][Status][Discuss] ...
- 【uoj#164】[清华集训2015]V 线段树维护历史最值
题目描述 给你一个长度为 $n$ 的序列,支持五种操作: $1\ l\ r\ x$ :将 $[l,r]$ 内的数加上 $x$ :$2\ l\ r\ x$ :将 $[l,r]$ 内的数减去 $x$ ,并 ...
- 【bzoj1858】[Scoi2010]序列操作 线段树区间合并
题目描述 lxhgww最近收到了一个01序列,序列里面包含了n个数,这些数要么是0,要么是1,现在对于这个序列有五种变换操作和询问操作: 0 a b 把[a, b]区间内的所有数全变成0 1 a b ...
- 【BZOJ2962】序列操作 线段树
[BZOJ2962]序列操作 Description 有一个长度为n的序列,有三个操作1.I a b c表示将[a,b]这一段区间的元素集体增加c,2.R a b表示将[a,b]区间内所有元素变成相反 ...
- UOJ #164 [清华集训2015]V (线段树)
题目链接 http://uoj.ac/problem/164 题解 神仙线段树题. 首先赋值操作可以等价于减掉正无穷再加上\(x\). 假设某个位置从前到后的操作序列是: \(x_1,x_2,..., ...
- 【BZOJ-1858】序列操作 线段树
1858: [Scoi2010]序列操作 Time Limit: 10 Sec Memory Limit: 64 MBSubmit: 1961 Solved: 991[Submit][Status ...
- BZOJ 1858: [Scoi2010]序列操作( 线段树 )
略恶心的线段树...不过只要弄清楚了AC应该不难.... ---------------------------------------------------------------- #inclu ...
随机推荐
- POJ 2486 Apple Tree [树状DP]
题目:一棵树,每个结点上都有一些苹果,且相邻两个结点间的距离为1.一个人从根节点(编号为1)开始走,一共可以走k步,问最多可以吃多少苹果. 思路:这里给出数组的定义: dp[0][x][j] 为从结点 ...
- Jenkins错误“to depth infinity with ignoreexternals:true”问题解决
试下以下解决方法: 1.可能是SVN插件版本过低导致,升级SVN插件. 2.可能是构建时自己手动修改了代码,而SVN检出时无法覆盖导致的错误,可以先删除jenkins检出的代码,然后再检出一次去构建. ...
- EasyMvc入门教程-基本控件说明(10)图片轮播导航
图片轮播导航大家一定很常见,尤其是中小型建站系统的必备神器..:) 先上图上例子,看效果如下: 实现代码如下: @{ var data = new List<PhotoPlayerItem> ...
- yii2操作数据库 mysql 读写分离 主从复制
转载地址:http://www.kuitao8.com/20150115/3471.shtml 开始使用数据库首先需要配置数据库连接组件,通过添加 db 组件到应用配置实现("基础的&quo ...
- js aop 拦载实现
var run = function(){ //is run } var aopBefore = function(){ //aopBefore } var tmpFn=run; run = func ...
- 【重点突破】——Canvas技术绘制音乐播放器界面
一.引言 在用Canvas练习制作了验证码之后,还有一个用Canvas技术很综合的练习——制作音乐播放器.在做这个练习的过程中,还有一个重要的观察点,那就是理解Canvas的一大问题. 二.要求 点 ...
- Performing User-Managed Database-18.7、Performing Complete User-Managed Media Recovery
18.7.Performing Complete User-Managed Media Recovery 完毕一致性备份,把数据库恢复到当前的scn是最好的结果.能够恢复整个数据库.恢复单个表空间.或 ...
- vuex 中关于 mapGetters 的作用
mapGetters 工具函数会将 store 中的 getter 映射到局部计算属性中.它的功能和 mapState 非常类似,我们来直接看它的实现: export function mapGett ...
- Java设计模式(九)责任链模式 命令模式
(十七)责任链模式 责任链模式的目的是通过给予多个对象处理请求的机会,已解除请求发送者与接受者之间的耦合关系.面对对象的开发力求对象之前保持松散耦合,确保对象各自的责任最小化.这种设计能够使得系统更加 ...
- 浅谈iOS中MVVM的架构设计与团队协作【转载】
今天写这篇文章是想达到抛砖引玉的作用,想与大家交流一下思想,相互学习,博文中有不足之处还望大家批评指正.本篇文章的内容沿袭以往博客的风格,也是以干货为主,偶尔扯扯咸蛋(哈哈~不好好工作又开始发表博客啦 ...