题面

洛谷P4229 某位歌姬的故事

\(T\) 组测试数据。有 \(n\) 个音节,每个音节 \(h_i\in[1,A]\),还有 \(m\) 个限制 \((l_i,r_i,g_i)\) 表示 \(\max_{k=l_i}^{r_i}h_k=g_i\)。求满足条件的 \(h_i\) 的方案数膜 \(998244353\)。

数据范围:\(1\le T\le 20\),\(1\le l_i\le r_i\le n\le 9\cdot 10^8\),\(1\le g_i\le A\le 9\cdot 10^8\),\(1\le m\le 500\)。


蒟蒻语

这是一眼题,蒟蒻 \(7\) 个小时就秒掉了。

题解做法时间复杂度 \(\Theta(Tm\log m)\)。


蒟蒻解

转化条件:\(\forall k\in[l_i,r_i],h_k\le g_i\) 并且 \(\exists k\in [l_i,r_i],h_k\ge g_i\)。

可以离散化,所以下文中可以把 \(n\) 看成与 \(m\) 相等的范围。

很明显对于 \(g_i<g_j\) 如果一个区间满足了 \(i\) 条件就无法满足 \(j\) 条件了,所以可以按 \(g\) 从小到大排序条件,每次处理完以后把区间删除;但是又会发现对于 \(g\) 相等的区间情况很复杂,所以可以排序后对每个 \(g\) 分开处理覆盖部分答案求积。删除区间可以用并查集(参考),然后最后对于每个没删除的音节答案乘以 \(A\) 即可。

然后只需假设 \(g\) 一定,并且区间覆盖全部音节。这时有多个棘手的条件,根据条件的形式容易想到子集反演

设 \(p=(\forall k\in[l_i,r_i],h_k\le g_i)\),\(q=(\exists k\in [l_i,r_i],h_k\ge g_i)\),所以:

\[p(S)\&q(S)=\sum_{T\in S}(-1)^{|T|}p(S-T)\neg q(T),\neg q(T)=(\forall k\in[l_i,r_i],h_k<g_i)
\]

这个子集反演是可以用 \(\rm dp\) 维护的,\(f(i,j)\) 表示 \(\forall k\in[i,j),h_k<g_i\) 前 \(i\) 个音节的方案数。

\[\forall j\le i,f(i,j)\leftarrow g\cdot f(i-1,j)
\]
\[\forall j> i,f(i,j)\leftarrow (g-1)\cdot f(i-1,j)
\]

假设有个以 \(i\) 为左端点的条件 \([i,t)\),可以用 \(\rm dp\) 维护反演老套路打个负标记并用类似 \(\rm min-max\) 卷积的方法:

\[\forall j,f(i,\max(j,t))\leftarrow f(i,\max(j,t))-f(i,j)
\]

操作比看起来简单:把 \(j\ge t\) 的 \(f(i,j)\) 直接置为 \(0\),然后 \(f(i,t)\leftarrow\sum_{j<t} f(i,j)=\sum f(i,j)\)。

然后是一波骚操作:把 \(i\) 这维滚掉(用离散化和并查集),然后线段树维护 \(j\) 这一维(啊!\(\rm dp\) 沦陷了!)。

最后还有个小细节:要把 \(g\) 相等但是 \([l_i,r_i]\in[l_j,r_j]\) 的 \(j\) 条件不放到 \(\rm dp\) 里,最后删除区间时统计。

时间复杂度 \(\Theta(Tm\log m)\)。 蒟蒻的题解都写成这样了,有人看得懂就怪了。


代码

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. //Start
  4. typedef long long ll;
  5. typedef double db;
  6. #define mp(a,b) make_pair((a),(b))
  7. #define x first
  8. #define y second
  9. #define be(a) (a).begin()
  10. #define en(a) (a).end()
  11. #define sz(a) int((a).size())
  12. #define pb(a) push_back(a)
  13. #define R(i,a,b) for(int i=(a),I=(b);i<I;i++)
  14. #define L(i,a,b) for(int i=(b)-1,I=(a)-1;i>I;i--)
  15. const int iinf=0x3f3f3f3f;
  16. const ll linf=0x3f3f3f3f3f3f3f3f;
  17. //Data
  18. const int Q=501,N=Q<<1,mod=998244353;
  19. int Pow(int a,int x){
  20. if(!a) return 0; int res=1;
  21. for(;x;a=1ll*a*a%mod,x>>=1)if(x&1) res=1ll*a*res%mod;
  22. return res;
  23. }
  24. int n,m,h,l[Q],r[Q],g[Q],dn,d[N],te[N+1];
  25. int find(int u){return u==te[u]?u:(te[u]=find(te[u]));}
  26. map<int,vector<int>> mp;
  27. //SegmentTree
  28. const int T=N<<2; int val[T],ml[T];
  29. #define mid ((l+r)>>1)
  30. void clear(int k=0,int l=0,int r=dn){
  31. val[k]=0,ml[k]=1; if(r-l==1) return;
  32. clear(k*2+1,l,mid),clear(k*2+2,mid,r);
  33. }
  34. void pushup(int k){(val[k]=val[k*2+1]+val[k*2+2])%=mod;}
  35. void pushmul(int k,int v){val[k]=1ll*val[k]*v%mod,ml[k]=1ll*ml[k]*v%mod;}
  36. void pushdown(int k){if(ml[k]^1) pushmul(k*2+1,ml[k]),pushmul(k*2+2,ml[k]),ml[k]=1;}
  37. void add(int x,int v,int k=0,int l=0,int r=dn){
  38. if(r<=x||x+1<=l) return; if(r-l==1) return void((val[k]+=v)%=mod);
  39. pushdown(k),add(x,v,k*2+1,l,mid),add(x,v,k*2+2,mid,r),pushup(k);
  40. }
  41. void mul(int x,int y,int v,int k=0,int l=0,int r=dn){
  42. if(r<=x||y<=l) return; if(x<=l&&r<=y) return pushmul(k,v);
  43. pushdown(k),mul(x,y,v,k*2+1,l,mid),mul(x,y,v,k*2+2,mid,r),pushup(k);
  44. }
  45. //DP
  46. int dp(int x,vector<int> a){
  47. mul(0,dn,0),add(0,1); vector<int> b;
  48. for(int i:a) l[i]=find(l[i]),r[i]=find(r[i]);
  49. sort(be(a),en(a),[&](int p,int q){return l[p]!=l[q]?l[p]<l[q]:r[p]<r[q];});
  50. for(int i:a){while(sz(b)&&r[b.back()]>=r[i]) b.pop_back();b.pb(i);}
  51. R(t,0,sz(b)){
  52. int i=find(l[b[t]]),j=find(r[b[t]]); if(i>=j) return 0;
  53. int ni=j;if(t+1<sz(b)) ni=min(ni,find(l[b[t+1]]));
  54. mul(j,dn,0),add(j,(mod-val[0])%mod);
  55. for(int k=i;k<ni;k=te[k]=find(k+1))
  56. mul(0,k+1,Pow(x,d[k+1]-d[k])),mul(k+1,dn,Pow(x-1,d[k+1]-d[k]));
  57. }
  58. int res=val[0];
  59. for(int i:a) for(int k=find(l[i]);k<find(r[i]);k=te[k]=find(k+1)) res=1ll*res*Pow(x,d[k+1]-d[k])%mod;
  60. return res;
  61. }
  62. //Main
  63. int Main(){
  64. cin>>n>>m>>h,dn=0,d[dn++]=0,d[dn++]=n,mp.clear();
  65. R(i,0,m) cin>>l[i]>>r[i]>>g[i],--l[i],d[dn++]=l[i],d[dn++]=r[i];
  66. sort(d,d+dn),dn=unique(d,d+dn)-d,clear();
  67. R(i,0,m) l[i]=lower_bound(d,d+dn,l[i])-d,r[i]=lower_bound(d,d+dn,r[i])-d,mp[g[i]].pb(i);
  68. iota(te,te+dn+1,0); int res=1;
  69. for(auto u:mp) res=1ll*res*dp(u.x,u.y)%mod;
  70. for(int k=find(0);k<dn-1;k=te[k]=find(k+1)) res=1ll*res*Pow(h,d[k+1]-d[k])%mod;
  71. return res;
  72. }
  73. int main(){
  74. ios::sync_with_stdio(0);
  75. cin.tie(0),cout.tie(0);
  76. int ta; cin>>ta; while(ta--) cout<<Main()<<'\n';
  77. return 0;
  78. }

祝大家学习愉快!

题解-洛谷P4229 某位歌姬的故事的更多相关文章

  1. Loj #2331. 「清华集训 2017」某位歌姬的故事

    Loj #2331. 「清华集训 2017」某位歌姬的故事 IA 是一名会唱歌的女孩子. IOI2018 就要来了,IA 决定给参赛选手们写一首歌,以表达美好的祝愿.这首歌一共有 \(n\) 个音符, ...

  2. 题解-洛谷P4859 已经没有什么好害怕的了

    洛谷P4859 已经没有什么好害怕的了 给定 \(n\) 和 \(k\),\(n\) 个糖果能量 \(a_i\) 和 \(n\) 个药片能量 \(b_i\),每个 \(a_i\) 和 \(b_i\) ...

  3. 题解 洛谷P5018【对称二叉树】(noip2018T4)

    \(noip2018\) \(T4\)题解 其实呢,我是觉得这题比\(T3\)水到不知道哪里去了 毕竟我比较菜,不大会\(dp\) 好了开始讲正事 这题其实考察的其实就是选手对D(大)F(法)S(师) ...

  4. 题解 洛谷P1562 【还是N皇后】

    原题:洛谷P1562 这个题的原理和8皇后的原理是一模一样的,就是必须要用n个皇后把每一个行填满,同时满足每一列,每一行,每一条对角线只有一个棋子.但如果按照原来的方法暴打的话只有60分(优化亲测无效 ...

  5. 题解 洛谷 P3396 【哈希冲突】(根号分治)

    根号分治 前言 本题是一道讲解根号分治思想的论文题(然鹅我并没有找到论文),正 如论文中所说,根号算法--不仅是分块,根号分治利用的思想和分块像 似却又不同,某一篇洛谷日报中说过,分块算法实质上是一种 ...

  6. 题解-洛谷P5410 【模板】扩展 KMP(Z 函数)

    题面 洛谷P5410 [模板]扩展 KMP(Z 函数) 给定两个字符串 \(a,b\),要求出两个数组:\(b\) 的 \(z\) 函数数组 \(z\).\(b\) 与 \(a\) 的每一个后缀的 L ...

  7. 题解-洛谷P4724 【模板】三维凸包

    洛谷P4724 [模板]三维凸包 给出空间中 \(n\) 个点 \(p_i\),求凸包表面积. 数据范围:\(1\le n\le 2000\). 这篇题解因为是世界上最逊的人写的,所以也会有求凸包体积 ...

  8. 题解-洛谷P5217 贫穷

    洛谷P5217 贫穷 给定长度为 \(n\) 的初始文本 \(s\),有 \(m\) 个如下操作: \(\texttt{I x c}\),在第 \(x\) 个字母后面插入一个 \(c\). \(\te ...

  9. 题解 洛谷 P2010 【回文日期】

    By:Soroak 洛谷博客 知识点:模拟+暴力枚举 思路:题目中有提到闰年然后很多人就认为,闰年是需要判断的其实,含有2月29号的回文串,前四位是一个闰年那么我们就可以直接进行暴力枚举 一些小细节: ...

随机推荐

  1. 测试:OGG初始化同步表,源端抽取进程scn<源端事务的start_scn时,这个变化是否会同步到目标库中?

    一.测试目标 疑问,OGG初始化同步表,源端抽取进程开始抽取的scn<源端事务的start_scn时,这个变化是否会同步到目标库中? 二.实验测试 如下进行测试! session 1 SQL&g ...

  2. Debian 64位内核升级步骤

    安装相关依赖包 apt-get install bzip2 libncurses5-dev kernel-package zlib1g-dev gcc make kernel-package wget ...

  3. nacos服务注册源码解析

    1.客户端使用 compile 'com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery:2.2.3.RELEASE' compi ...

  4. ASP.NET Core使用HostingStartup增强启动操作

    概念 在ASP.NET Core中我们可以使用一种机制来增强启动时的操作,它就是HostingStartup.如何叫"增强"操作,相信了解过AOP概念的同学应该都非常的熟悉.我们常 ...

  5. Monitor的扩展支持string的超时锁

    对Monitor的使用可以防止lock的时间过长并且可以设置其对应的超时时间达到对预期代码的一个控制,合理的使用timeout可以有助于程序的健壮性.但是对于不同的并发程序可能某些时候我们需要的粒度是 ...

  6. [原题复现]百度杯CTF比赛 十月场 WEB EXEC(PHP弱类型)

    简介  原题复现:  考察知识点:PHP弱类型.  线上平台:https://www.ichunqiu.com/battalion(i春秋 CTF平台) 过程 看源码发现这个 vim泄露  下方都试了 ...

  7. Vegas常见问题解答,如何处理预览卡顿

    制作视频并不是简单的拼拼凑凑,很多时候我们都需要给视频加上一些视频特效或转场等效果,如果只是图片素材的话,还不会出现卡顿的现象,但是当你给视频添加了效果后,在预览窗口看到的就是非常卡顿了.除了本身计算 ...

  8. 在FL Studio中有序地处理人声的混音轨道

    关于人声处理的技巧,我们在以前也有讲到很多,当然在以后也会有新的人声处理技巧课程,这是在音乐后期制作中无法避免的一个环节,在制作许多流行音乐时都会用到,今天先为大家讲解一下在FL Studio中更有序 ...

  9. JDBC【2】-- JDBC工作原理以及简单封装

    目录 1. 工作原理 1.1 加载驱动 1.1.1 类加载相关知识 1.1.2 为什么JDK 1.6之后不需要显示加载了? 1.2 驱动加载完成了,然后呢? 2. 简单封装 1. 工作原理 一般我们主 ...

  10. 【mq读书笔记】Index索引文件

    1.IndexHeader头部,40字节,记录IndexFile的统计信息: begainTimestamp:该索引文件中包含消息的最小存储时间 endTimestamp:该索引文件中包含消息的最大存 ...