Description

Solution

有两种做法

一种是线段树维护一次方程系数,一种是线段树维护矩阵

准备都写一写


维护系数

首先把式子推出来 $$CS=B\times \sum\limits_{i=1}^np_i\times(f_{i-1}+1)$$

\[f_i=(t+p_i-p_i\times t)\times f_{i-1}+p_i
\]

发现 \(f_i\) 是关于 \(f_{i-1}\) 的一次函数 \(y=kx+b\) 形式,可以线段树维护这个 \(k\) 和 \(b\)。

还有 \(p_i\times(f_{i-1}+1)=p_i\times f_{i-1}+p_i\) 也是个一次函数,也能用线段树维护。

具体都维护些什么呢?

在区间 \([L,R]\) 维护 \(k_1,b_1\) 表示 \(f_R=k_1f_{L-1}+b_1\) 和 \(k_2,b_2\) 表示 \(CS[L,R]=k_2f_{L-1}+b_2\)

观察到这样做的好处就是右区间的 \(L-1\) 等于左区间的 \(R\),这样就资瓷快速合并了。

然后如果一个询问是 \([l,r]\),那求出来的 \(CS[L,R]\) 的 \(b_2\) 就是答案了。

  1. #include<set>
  2. #include<map>
  3. #include<cmath>
  4. #include<queue>
  5. #include<cctype>
  6. #include<vector>
  7. #include<cstdio>
  8. #include<cstring>
  9. #include<iostream>
  10. #include<algorithm>
  11. using std::min;
  12. using std::max;
  13. using std::swap;
  14. using std::vector;
  15. typedef double db;
  16. const int N=500005;
  17. typedef long long ll;
  18. const int mod=998244353;
  19. #define pb(A) push_back(A)
  20. #define pii std::pair<int,int>
  21. #define mp(A,B) std::make_pair(A,B)
  22. #define ls cur<<1
  23. #define rs cur<<1|1
  24. #define lss ls,l,mid,ql,qr
  25. #define rss rs,mid+1,r,ql,qr
  26. int n,q,t,tb,A,B,b1[N<<2],b2[N<<2];
  27. int p[N],sump[N<<2],k1[N<<2],k2[N<<2];
  28. struct Node{
  29. int sump,k1,b1,k2,b2;
  30. friend Node operator+(Node x,Node y){
  31. Node z;
  32. z.sump=(x.sump+y.sump)%mod;
  33. z.k1=(ll)y.k1*x.k1%mod;
  34. z.b1=((ll)y.k1*x.b1%mod+y.b1)%mod;
  35. z.k2=((ll)y.k2*x.k1%mod+x.k2)%mod;
  36. z.b2=((ll)y.k2*x.b1%mod+y.b2+x.b2)%mod;
  37. return z;
  38. }
  39. };
  40. int getint(){
  41. int X=0,w=0;char ch=0;
  42. while(!isdigit(ch))w|=ch=='-',ch=getchar();
  43. while( isdigit(ch))X=X*10+ch-48,ch=getchar();
  44. if(w) return -X;return X;
  45. }
  46. int ksm(int x,int y){
  47. int ans=1;
  48. while(y){
  49. if(y&1) ans=(ll)ans*x%mod;
  50. x=(ll)x*x%mod;y>>=1;
  51. } return ans;
  52. }
  53. int inv(int x){
  54. return ksm(x,mod-2);
  55. }
  56. void pushup(int cur){
  57. k1[cur]=(ll)k1[rs]*k1[ls]%mod;
  58. b1[cur]=((ll)k1[rs]*b1[ls]%mod+b1[rs])%mod;
  59. k2[cur]=((ll)k2[rs]*k1[ls]%mod+k2[ls])%mod;
  60. b2[cur]=((ll)k2[rs]*b1[ls]%mod+(ll)b2[rs]+b2[ls])%mod;
  61. sump[cur]=((ll)sump[ls]+sump[rs])%mod;
  62. }
  63. void build(int cur,int l,int r){
  64. if(l==r){
  65. k1[cur]=((ll)t+p[l]-(ll)p[l]*t%mod+mod)%mod;
  66. b1[cur]=p[l];
  67. k2[cur]=p[l];
  68. b2[cur]=p[l];
  69. sump[cur]=p[l];
  70. return;
  71. } int mid=l+r>>1;
  72. build(ls,l,mid);build(rs,mid+1,r);
  73. pushup(cur);
  74. }
  75. void modify(int cur,int l,int r,int ql,int qr,int c){
  76. if(l==r){
  77. k1[cur]=((ll)t+c-(ll)c*t%mod+mod)%mod;
  78. b1[cur]=k2[cur]=b2[cur]=sump[cur]=c;
  79. return;
  80. } int mid=l+r>>1;
  81. ql<=mid?modify(lss,c):modify(rss,c);
  82. pushup(cur);
  83. }
  84. Node query(int cur,int l,int r,int ql,int qr){
  85. if(ql<=l and r<=qr) return (Node){sump[cur],k1[cur],b1[cur],k2[cur],b2[cur]};
  86. int mid=l+r>>1;
  87. if(qr<=mid) return query(lss);
  88. if(ql>mid) return query(rss);
  89. return query(lss)+query(rss);
  90. }
  91. signed main(){
  92. freopen("omeed.in","r",stdin);freopen("omeed.out","w",stdout);
  93. getint();n=getint(),q=getint(),t=getint(),tb=getint(),A=getint(),B=getint();
  94. t=(ll)t*inv(tb)%mod;
  95. for(int i=1;i<=n;i++){
  96. int x=getint(),y=getint();
  97. p[i]=(ll)x*inv(y)%mod;
  98. } build(1,1,n);
  99. while(q--){
  100. if(getint()==0){
  101. int pos=getint(),a=getint(),b=getint(),c=(ll)a*inv(b)%mod;
  102. p[pos]=c;modify(1,1,n,pos,pos,c);
  103. } else{
  104. int l=getint(),r=getint();
  105. Node ans=query(1,1,n,l,r);
  106. printf("%d\n",((ll)ans.sump*A%mod+(ll)ans.b2*B%mod)%mod);
  107. }
  108. } return 0;
  109. }

维护矩阵

上面的DP式子已经列出来了。

我们现在要解决的这样一类问题:我们知道DP式子,现在要求多次从不同的起点开始做DP

求出DP的转移矩阵然后线段树上动态DP就好了

姿势不对会T一个点懒得卡常了

  1. #include<set>
  2. #include<map>
  3. #include<cmath>
  4. #include<queue>
  5. #include<cctype>
  6. #include<vector>
  7. #include<cstdio>
  8. #include<cstring>
  9. #include<iostream>
  10. #include<algorithm>
  11. using std::min;
  12. using std::max;
  13. using std::swap;
  14. using std::vector;
  15. typedef double db;
  16. const int N=500005;
  17. const int mod=998244353;
  18. typedef long long ll;
  19. #define pb(A) push_back(A)
  20. #define pii std::pair<Mat,int>
  21. #define mp(A,B) std::make_pair(A,B)
  22. #define ls cur<<1
  23. #define rs cur<<1|1
  24. #define lss ls,l,mid,ql,qr
  25. #define rss rs,mid+1,r,ql,qr
  26. int n,q,t,ta,A,B;
  27. int p[N],sum[N<<2];
  28. struct Mat{
  29. int a[4][4];
  30. void clear(){
  31. memset(a,0,sizeof a);
  32. }
  33. void init(){
  34. clear();
  35. for(int i=1;i<=3;i++) a[i][i]=1;
  36. }
  37. friend Mat operator*(Mat x,Mat y){
  38. Mat z;z.clear();
  39. for(int i=1;i<=3;i++)
  40. for(int k=1;k<=3;k++)
  41. for(int j=1;j<=3;j++)
  42. z.a[i][j]=((ll)z.a[i][j]+(ll)x.a[i][k]*y.a[k][j]%mod)%mod;
  43. return z;
  44. }
  45. }cs[N<<2];
  46. void pushup(int cur){
  47. cs[cur]=cs[ls]*cs[rs];
  48. sum[cur]=(sum[ls]+sum[rs])%mod;
  49. }
  50. void build(int cur,int l,int r){
  51. if(l==r){
  52. cs[cur].a[1][1]=((ll)p[l]+t-(ll)p[l]*t%mod+mod)%mod;cs[cur].a[1][2]=(ll)B*p[l]%mod;cs[cur].a[1][3]=0;
  53. cs[cur].a[2][1]=0;cs[cur].a[2][2]=1;cs[cur].a[2][3]=0;sum[cur]=p[l];
  54. cs[cur].a[3][1]=p[l];cs[cur].a[3][2]=(ll)p[l]*(B+A)%mod;cs[cur].a[3][3]=1;
  55. return;
  56. } int mid=l+r>>1;
  57. build(ls,l,mid);build(rs,mid+1,r);pushup(cur);
  58. }
  59. void modify(int cur,int l,int r,int ql,int qr,int c){
  60. if(l==r){
  61. cs[cur].a[1][1]=((ll)c+t-(ll)c*t%mod+mod)%mod;cs[cur].a[1][2]=(ll)B*c%mod;cs[cur].a[1][3]=0;
  62. cs[cur].a[2][1]=0;cs[cur].a[2][2]=1;cs[cur].a[2][3]=0;sum[cur]=c;
  63. cs[cur].a[3][1]=c;cs[cur].a[3][2]=(ll)c*(B+A)%mod;cs[cur].a[3][3]=1;return;
  64. } int mid=l+r>>1;
  65. ql<=mid?modify(lss,c):modify(rss,c);
  66. pushup(cur);
  67. }
  68. Mat query(int cur,int l,int r,int ql,int qr){
  69. if(ql<=l and r<=qr) return cs[cur];
  70. int mid=l+r>>1;
  71. if(qr<=mid) return query(lss);
  72. if(ql>mid) return query(rss);
  73. return query(lss)*query(rss);
  74. }
  75. int getint(){
  76. int X=0,w=0;char ch=0;
  77. while(!isdigit(ch))w|=ch=='-',ch=getchar();
  78. while( isdigit(ch))X=X*10+ch-48,ch=getchar();
  79. if(w) return -X;return X;
  80. }
  81. int ksm(int a,int y){
  82. int ans=1;
  83. while(y){
  84. if(y&1) ans=(ll)ans*a%mod;
  85. a=(ll)a*a%mod;y>>=1;
  86. } return ans;
  87. }
  88. int inv(int x){
  89. return ksm(x,mod-2);
  90. }
  91. signed main(){
  92. getint(),n=getint(),q=getint(),t=getint(),ta=getint(),A=getint(),B=getint();
  93. t=(ll)t*inv(ta)%mod;
  94. for(int i=1;i<=n;i++){
  95. int x=getint(),y=getint();
  96. p[i]=(ll)x*inv(y)%mod;
  97. } build(1,1,n);
  98. while(q--){
  99. if(getint()==0){
  100. int pos=getint(),x=getint(),y=getint(),z=(ll)x*inv(y)%mod;
  101. modify(1,1,n,pos,pos,z);
  102. } else{
  103. int l=getint(),r=getint();
  104. printf("%d\n",query(1,1,n,l,r).a[3][2]);
  105. }
  106. } return 0;
  107. }

[JZOJ5837] Omeed的更多相关文章

  1. [JZOJ] 5837.Omeed

    先摆出来这个式子 \[ score=A\sum S_i+B\sum S_i\times f(i) \] 先研究\(f\)函数(也就是Combo函数) 显然的有 \[ f(i)=P_i(f(i-1)+1 ...

  2. 20210824 Prime,Sequence,Omeed

    考场 T1 貌似是 luogu 上原题 T2 计数,想起了这题和这题,但没有 \(n^2\) 一档的分...准备打个表 T3 期望 DP,但暴力是 \(O(qn)\) 的,发现 \(combo\) 的 ...

  3. Omeed 线段树

    目录 题面 题解 代码 题面 2.12 - - - 题解 大概还是挺妙的? 首先基础分和连击分互不干扰,所以可以分开统计. 基础分的统计比较简单,等于: \[A \sum_{i = l}^{r} p_ ...

  4. 题解 Omeed

    传送门 差了一点没想到正解-- 首先单次询问的 \(O(n)\) 写法很好想,考虑如何优化 首先基础分区间求和即可 然后那个连击分的话,是一个关于 \(f_i\) 和 \(f_{i-1}\) 的柿子 ...

  5. [考试总结]noip模拟47

    感觉自己放弃题目还是过于容易. 其实第一题不是很难,但是自己拿了一个暴力就走人了.. 然后其实简单优化一下子就有不少分数. 然后第二题的本质不同的子序列个数的方程没有推出来,如果推出来就会直接有 \( ...

  6. Noip模拟47 2021.8.25

    期望得分:55+24+53 实际得分:0+0+3 乐死 累加变量清零了吗? 打出更高的部分分暴力删了吗? 样例解释换行你看见了吗? T1 Prime 打出55分做法没删原来的暴力,结果就轻松挂55分 ...

  7. 2021.8.24考试总结[NOIP47]

    T1 prime 发现只需筛小于等于$mid(\sqrt r,k)$的质数,之后用这些质数筛掉区间内不合法的数即可. $code:$ 1 #include<bits/stdc++.h> 2 ...

随机推荐

  1. js将数组根据条件分组

    //将数组根据条件分组 function getTreeDateByParam(list, param, fun){ var data = {}; if(list && list.le ...

  2. boost--内存池

    boost的内存池实现了一个快速.紧凑的内存分配和管理器,使用它可以完全不用考虑delete释放问题.常用的boost内存池有pool.object_pool.singleton_pool. 1.po ...

  3. webpack Cannot find module 'webpack/schemas/WebpackOptions.json'

    webpack-dev-server版本的问题 一直在解决这个问题,最后竟然发现...安装2.9.1版本就可以了 npm install webpack-dev-server@2.9.1

  4. [solution] JZOJ-5458 质数

    [solution] JZOJ-5458 质数 题面 Description 小X 是一位热爱数学的男孩子,在茫茫的数字中,他对质数更有一种独特的情感.小X 认为,质数是一切自然数起源的地方. 在小X ...

  5. Html5与Css3知识点拾遗(八)

    css5新增的元素与属性 表单内元素的属性 1. form属性 之前必须书写在表单内部.而在Html5中,可以放在任何位置,为元素指定一个form属性,属性值为该表单的id,就可以声明该元素属于指定表 ...

  6. cf 700e(sam好题,线段树维护right)

    代码参考:http://blog.csdn.net/qq_33229466/article/details/79140428 #include<iostream> #include< ...

  7. MFC开发中添加自定义消息和消息响应函数

    (1)在.h或.cpp文件定义一个消息 #define CLICK_MESSAGE_BOX WM_USER+1001 //add by 20180612 给主窗口ctrl.cpp发送消息 //自定义消 ...

  8. re、词云

    正则:   re.S使点也能匹配到\n:re.I不区分规则中的大小写:re.X忽略空格及#后的注释:re.M把^和$由文首文末变为各行的首尾.   Egの删除各行行尾的alex,alex不区分大小写: ...

  9. (转载)RHEL7(RedHat 7)本地源的配置

    配置yum源 1.首先连接RedHat7的DVD再把挂载DVD光盘到/mnt   因为配置时候路径名里面不能有空格,否则不能识别  [root@ mnt]# mount /dev/cdrom /mnt ...

  10. Adobe reader multiple languages pack

    用户打开客户发过来的PDF文档,显示不正常,这是电脑的Adobe Reader缺少相关的字体. 可以从下面地址下载相对版本的字体包安装:http://supportdownloads.adobe.co ...