Codeforces 题面传送门 & 洛谷题面传送门

大模拟(?)+阿巴细节题,模拟赛时刚了 3h 最后因为某个细节写挂 100->40/ll/ll(下次一定不能再挂分了啊 awa)

首先先考虑怎么判 \(-1\),显然如果区间 \([l,r]\) 中间的括号构不成合法的括号序列,答案显然是 \(-1\),其次如果 \(s_l\) 是加号或乘号那算式也不合法,\(s_r\) 也同理,这可以通过前缀和+ST 表在 \(\mathcal O(n\log n)-\mathcal O(1)\) 时间内判断。

其次考虑怎样计算一个表达式的值,首先按照套路建出表达式树,不过这里建表达式树与平常略微有点不同,平常我们建的表达式树都是二叉树,即将运算符放在中间,参与运算的两个部分作为该节点的左右儿子,这次咱们偏不建二叉树,咱们建多叉树,具体来说,对于同一个括号内的统计运算我们同时将它们设为该运算代表的节点的儿子(比方说 \(1+2\times 3+4\times 5\) 的根节点就有 \(3\) 个儿子 \(1,2\times 3,4\times 5\),中间运算符为加号),我们同时记录这些儿子执行的运算在原字符串中对于的区间,比方说 \(2\times 3\) 这个儿子在原字符串中的区间就是 \([3,5]\)。

那么对于一个询问而言,如果它本身就是一个数(比方说 \(1234\) 或 \((((7)))\))那么我们就直接输出这个数即可,否则我们找出计算这个表达式时最后一次执行的运算表示的节点 \(x\),显然 \(x\) 表示的运算有加号或乘号两种可能,分情况讨论:

首先考虑乘法,我们假设 \(x\) 的儿子在原字符串中的区间分别为 \([a_1,b_1],[a_2,b_2],\cdots,[a_m,b_m]\),那么我们二分找出 \(l,r\) 所在的区间,假设为 \([a_L,b_L]\) 和 \([a_R,b_R]\),显然这些区间在 \([l,r]\) 中的部分是一个个整段+边上两个散块,中间部分对答案的贡献显然是完整的,直接前缀积即可 \(\mathcal O(1)\) 求出,注意特判前缀积为 \(0\) 的情况,此时需记录前缀 \(0\) 的个数加以判断,对于边上两块的情况分情况讨论:有可能两边也是整块贡献,这时候直接计入答案即可,也有可能两边是某一段数计入贡献(比方说 \(12\times 34\times 56\),对于询问 \([2,7]\) 而言,左边的 \(12\) 和右边的 \(56\) 就分别被一分为二),此时写一个类似哈希的东西快速求出一段区间表示的数即可在常数时间内累加贡献。

接下来考虑加法,和乘法类似,我们还是找出 \(l,r\) 所在的区间 \([a_L,b_L]\) 和 \([a_R,b_R]\),这些区间在 \([l,r]\) 中的部分还是一个个整段+边上两个散块,对于中间部分对前缀和搞一下即可,对于边上两块的情况还是分情况讨论:前两类(整块贡献&某个数一分为二)与乘法一样不再赘述,但是加法比乘法多的一种情况是,有可能边角块对应的运算是一个序列的乘法运算(比方说 \(12\times 34+56\times 78\) 对于询问 \([2,10]\) 而言,左边区间计入贡献的部分就是 \(2\times 34\),右边部分也同理),以左边的散块为例,这种情况就找到 \([a_L,b_L]\) 对应的节点,二分一下乘法对应的区间(显然是一段后缀),然后还是前缀积算一算即可,注意,在这部分里的乘法操作中还是有可能出现某个数一分为二的情况,注意判断。

时间复杂度 \(n\log n\),注意特判一些奇奇怪怪的情况,比方说 \(((((((1145141919810))))))\) 或者 \((998244353)\times (19260817)\),我就是因为这边有个细节写挂了而丢了 60pts/ll

代码(码了 238 行,现以吊打切树游戏、吊打 CF788E,荣膺我 AC 的题目中的码量之最)

  1. const int MAXN=5e5;
  2. const int LOG_N=20;
  3. const int MOD=1e9+7;
  4. int qpow(int x,int e){
  5. int ret=1;
  6. for(;e;e>>=1,x=1ll*x*x%MOD) if(e&1) ret=1ll*ret*x%MOD;
  7. return ret;
  8. }
  9. int n,qu,ncnt,sum[MAXN+5],dep[MAXN+5];char s[MAXN+5];
  10. int nt[MAXN+5],pr[MAXN+5];
  11. vector<int> son[MAXN+5];
  12. vector<pii> itvl[MAXN+5];
  13. int mch[MAXN+5],rt,bel[MAXN+5],op[MAXN+5],val[MAXN+5];
  14. int pre[MAXN+5],pw10[MAXN+5];
  15. int getnum(int l,int r){return (pre[r]-1ll*pre[l-1]*pw10[r-l+1]%MOD+MOD)%MOD;}
  16. int build(int l,int r){
  17. if(s[l]=='('&&mch[l]==r) return bel[l]=bel[r]=build(l+1,r-1);
  18. int opt=-1,id=++ncnt;
  19. for(int i=l;i<=r;){
  20. if(s[i]=='+') opt=0;
  21. else if(s[i]=='*'&&!~opt) opt=1;
  22. if(s[i]=='(') i=mch[i]+1;
  23. else i++;
  24. } op[id]=opt;
  25. if(!~opt){
  26. for(int i=l;i<=r;i++){
  27. bel[i]=id;
  28. val[id]=(10ll*val[id]+s[i]-'0')%MOD;
  29. } return id;
  30. } int pre=l-1;
  31. for(int i=l;i<=r;){
  32. if((s[i]=='+'&&!opt)||(s[i]=='*'&&opt)){
  33. son[id].pb(build(pre+1,i-1));
  34. itvl[id].pb(mp(pre+1,i-1));
  35. pre=i;bel[i]=id;
  36. } if(s[i]=='(') i=mch[i]+1;
  37. else i++;
  38. } son[id].pb(build(pre+1,r));itvl[id].pb(mp(pre+1,r));
  39. // printf("build [%d,%d]:\n",l,r);
  40. // printf("op[%d]=%d\n",id,op[id]);
  41. // for(int x:son[id]) printf("%d ",x);printf("\n");
  42. // for(pii p:itvl[id]) printf("[%d,%d]\n",p.fi,p.se);
  43. // printf("\n");
  44. return id;
  45. }
  46. struct num0{
  47. int x,y;
  48. num0(int _x=0){(_x)?(x=_x,y=0):(x=y=1);}
  49. int val(){return (y)?0:x;}
  50. num0 operator +(const int &rhs){
  51. int sum=(val()+rhs)%MOD;
  52. return (sum)?num0(sum):num0(0);
  53. }
  54. num0 operator *(const int &rhs){
  55. num0 res=*this;
  56. (rhs)?(res.x=1ll*res.x*rhs%MOD):(res.y++);
  57. return res;
  58. }
  59. num0 operator /(const num0 &rhs){
  60. num0 res;res.x=1ll*x*qpow(rhs.x,MOD-2)%MOD;
  61. res.y=y-rhs.y;return res;
  62. }
  63. };
  64. vector<num0> ss[MAXN+5];
  65. void calc(int x){
  66. if(~op[x]) val[x]=op[x];
  67. ss[x].resize(son[x].size());
  68. for(int i=0;i<son[x].size();i++){
  69. int y=son[x][i];dep[y]=dep[x]+1;calc(y);
  70. if(!i) ss[x][i]=val[y];
  71. if(op[x]==0){
  72. val[x]=(val[x]+val[y])%MOD;
  73. if(i) ss[x][i]=ss[x][i-1]+val[y];
  74. } else {
  75. val[x]=1ll*val[x]*val[y]%MOD;
  76. if(i) ss[x][i]=ss[x][i-1]*val[y];
  77. }
  78. // printf("%d %d %d\n",x,i,ss[x][i].val());
  79. }
  80. }
  81. int st_sum[MAXN+5][LOG_N+2];
  82. pii st_dep[MAXN+5][LOG_N+2];
  83. void buildst(){
  84. for(int i=1;i<=LOG_N;i++) for(int j=1;j+(1<<i)-1<=n;j++){
  85. st_sum[j][i]=min(st_sum[j][i-1],st_sum[j+(1<<i-1)][i-1]);
  86. st_dep[j][i]=min(st_dep[j][i-1],st_dep[j+(1<<i-1)][i-1]);
  87. }
  88. }
  89. int query_sum(int l,int r){
  90. int k=31-__builtin_clz(r-l+1);
  91. return min(st_sum[l][k],st_sum[r-(1<<k)+1][k]);
  92. }
  93. pii query_dep(int l,int r){
  94. int k=31-__builtin_clz(r-l+1);
  95. return min(st_dep[l][k],st_dep[r-(1<<k)+1][k]);
  96. }
  97. int main(){
  98. // freopen("calc.in","r",stdin);
  99. // freopen("calc.out","w",stdout);
  100. scanf("%s%d",s+1,&qu);n=strlen(s+1);
  101. for(int i=1;i<=n;i++){
  102. if(isdigit(s[i])) pre[i]=(10ll*pre[i-1]+s[i]-'0')%MOD;
  103. else pre[i]=pre[i-1];
  104. }
  105. for(int i=(pw10[0]=1);i<=n;i++) pw10[i]=10ll*pw10[i-1]%MOD;
  106. stack<int> stk;
  107. for(int i=1;i<=n;i++){
  108. if(s[i]=='(') stk.push(i),sum[i]=sum[i-1]+1;
  109. else if(s[i]==')'){
  110. mch[i]=stk.top();mch[stk.top()]=i;
  111. stk.pop();sum[i]=sum[i-1]-1;
  112. } else sum[i]=sum[i-1];
  113. }
  114. int pp=n+1;
  115. for(int i=n;i;i--){
  116. if(!isdigit(s[i])) pp=i;
  117. else nt[i]=pp-1;
  118. } pp=0;
  119. for(int i=1;i<=n;i++){
  120. if(!isdigit(s[i])) pp=i;
  121. else pr[i]=pp+1;
  122. }
  123. // for(int i=1;i<=n;i++) printf("%d%c",mch[i]," \n"[i==n]);
  124. rt=build(1,n);calc(rt);
  125. // for(int i=1;i<=n;i++) printf("%d%c",bel[i]," \n"[i==n]);
  126. for(int i=1;i<=n;i++) st_sum[i][0]=sum[i],st_dep[i][0]=mp(dep[bel[i]],i);
  127. buildst();
  128. while(qu--){
  129. int l,r;scanf("%d%d",&l,&r);
  130. if(sum[l-1]!=sum[r]){puts("-1");continue;}
  131. if(query_sum(l,r)<sum[l-1]){puts("-1");continue;}
  132. if(s[l]=='+'||s[l]=='*'){puts("-1");continue;}
  133. if(s[r]=='+'||s[r]=='*'){puts("-1");continue;}
  134. pii p=query_dep(l,r);int x=bel[p.se];
  135. // printf("%d\n",x);
  136. if(!~op[x]){
  137. if(isdigit(s[l])&&isdigit(s[r])) printf("%d\n",getnum(l,r));
  138. else printf("%d\n",val[x]);
  139. continue;
  140. }
  141. int L=upper_bound(itvl[x].begin(),itvl[x].end(),mp(l,n+1))-itvl[x].begin()-1;
  142. int R=upper_bound(itvl[x].begin(),itvl[x].end(),mp(r,n+1))-itvl[x].begin()-1;
  143. if(L<0) L=0;
  144. int u=son[x][L],v=son[x][R];
  145. // printf("%d %d\n",L,R);
  146. if(op[x]==1){
  147. int res=1;
  148. if(L!=R){
  149. num0 qwq=ss[x][R-1]/ss[x][L];
  150. res=qwq.val();
  151. }
  152. if(~op[u]) res=1ll*res*val[u]%MOD;
  153. else{
  154. if(isdigit(s[l])) res=1ll*res*getnum(l,nt[l])%MOD;
  155. else res=1ll*res*val[u]%MOD;
  156. } if(~op[v]) res=1ll*res*val[v]%MOD;
  157. else{
  158. if(isdigit(s[r])) res=1ll*res*getnum(pr[r],r)%MOD;
  159. else res=1ll*res*val[v]%MOD;
  160. }
  161. printf("%d\n",res);
  162. } else {
  163. int res=0;
  164. if(L!=R) res=(ss[x][R-1].val()-ss[x][L].val()+MOD)%MOD;
  165. if(~op[u]){
  166. if(op[u]==0) res=(res+val[u])%MOD;
  167. else{
  168. int LL=upper_bound(itvl[u].begin(),itvl[u].end(),mp(l,n+1))-itvl[u].begin()-1;
  169. if(LL<0) LL=0;
  170. int su=son[u][LL],mul=1;
  171. if(LL+1!=ss[u].size())
  172. mul=(ss[u].back()/ss[u][LL]).val();
  173. if(~op[su]) mul=1ll*mul*val[su]%MOD;
  174. else{
  175. if(isdigit(s[l])) mul=1ll*mul*getnum(l,nt[l])%MOD;
  176. else mul=1ll*mul*val[su]%MOD;
  177. }
  178. res=(res+mul)%MOD;
  179. }
  180. } else{
  181. if(isdigit(s[l])) res=(res+getnum(l,nt[l]))%MOD;
  182. else res=(res+val[u])%MOD;
  183. }
  184. if(~op[v]){
  185. if(op[v]==0) res=(res+val[v])%MOD;
  186. else{
  187. int RR=upper_bound(itvl[v].begin(),itvl[v].end(),mp(r,n+1))-itvl[v].begin()-1;
  188. int sv=son[v][RR],mul=1;
  189. if(RR) mul=(ss[v][RR-1]).val();
  190. if(~op[sv]) mul=1ll*mul*val[sv]%MOD;
  191. else{
  192. if(isdigit(s[r])) mul=1ll*mul*getnum(pr[r],r)%MOD;
  193. else mul=1ll*mul*val[sv]%MOD;
  194. }
  195. res=(res+mul)%MOD;
  196. }
  197. } else{
  198. if(isdigit(s[r])) res=(res+getnum(pr[r],r))%MOD;
  199. else res=(res+val[v])%MOD;
  200. }
  201. printf("%d\n",res);
  202. }
  203. }
  204. return 0;
  205. }

Codeforces 730L - Expression Queries(大模拟)的更多相关文章

  1. HDU 5920 Ugly Problem 高精度减法大模拟 ---2016CCPC长春区域现场赛

    题目链接 题意:给定一个很大的数,把他们分为数个回文数的和,分的个数不超过50个,输出个数并输出每个数,special judge. 题解:现场赛的时候很快想出来了思路,把这个数从中间分为两部分,当位 ...

  2. AC日记——神奇的幻方 洛谷 P2615(大模拟)

    题目描述 幻方是一种很神奇的N*N矩阵:它由数字1,2,3,……,N*N构成,且每行.每列及两条对角线上的数字之和都相同. 当N为奇数时,我们可以通过以下方法构建一个幻方: 首先将1写在第一行的中间. ...

  3. ACdream 1188 Read Phone Number (字符串大模拟)

    Read Phone Number Time Limit:1000MS     Memory Limit:64000KB     64bit IO Format:%lld & %llu Sub ...

  4. [Codeforces]817F. MEX Queries 离散化+线段树维护

    [Codeforces]817F. MEX Queries You are given a set of integer numbers, initially it is empty. You sho ...

  5. CodeForces.158A Next Round (水模拟)

    CodeForces.158A Next Round (水模拟) 题意分析 校赛水题的英文版,坑点就是要求为正数. 代码总览 #include <iostream> #include &l ...

  6. 2016ACM-ICPC网络赛北京赛区 1001 (trie树牌大模拟)

    [题目传送门] 1383 : The Book List 时间限制:1000ms 单点时限:1000ms 内存限制:256MB 描述 The history of Peking University ...

  7. Bzoj1972: [Sdoi2010]猪国杀 题解(大模拟+耐心+细心)

    猪国杀 - 可读版本 https://mubu.com/doc/2707815814591da4 题目可真长,读题都要一个小时. 这道题很多人都说不可做,耗时间,代码量大,于是,本着不做死就不会死的精 ...

  8. (大模拟紫题) Luogu P1953 易语言

    原题链接:P1953 易语言 (我最近怎么总在做大模拟大搜索题) 分别处理两种情况. 如果只有一个1或0 直接设一个cnt为这个值,每次输入一个新名字之后把数字替换成cnt,最后cnt++即可. 注意 ...

  9. [Codeforces 266E]More Queries to Array...(线段树+二项式定理)

    [Codeforces 266E]More Queries to Array...(线段树+二项式定理) 题面 维护一个长度为\(n\)的序列\(a\),\(m\)个操作 区间赋值为\(x\) 查询\ ...

随机推荐

  1. HTTP标签

    系统的http状态码知识,我是在<图解http里学习的>. 状态码的职责是告知从服务器端返回的请求结果. 分类如下: 2XX --> 成功 200 OK(一般情况) 204 No C ...

  2. UltraSoft - Alpha - Scrum Meeting 1

    Date: Apr 06th, 2020. 会议内容为讨论功能规格书和技术规格书的撰写. Scrum 情况汇报 进度情况 组员 负责 昨日进度 后两日任务 CookieLau PM.后端 进行Djan ...

  3. 扩展spring data jpa的repository

    在我们编写代码的过程中,spring data jpa为我们的持久层提供的极大的方便,但有时spring data jpa提供的repository并不能完全满足我们开发的需求,因此就需要进行扩展.s ...

  4. Python网络爬虫实战入门

    一.网络爬虫 网络爬虫(又被称为网页蜘蛛,网络机器人),是一种按照一定的规则,自动地抓取万维网信息的程序. 爬虫的基本流程: 发起请求: 通过HTTP库向目标站点发起请求,也就是发送一个Request ...

  5. Java并发:重入锁 ReentrantLock(二)

    一.理解锁的实现原理 1. 用wait()去实现一个lock方法,wait()要和synchronized同步关键字一起去使用的,直接使用wait方法会直接报IllegalMonitorStateEx ...

  6. C++实现红黑树

    红黑树的应用: 利用key_value对,快速查找,O(logn) socket与客户端id之间,形成映射关系(socket, id) 内存分配管理 一整块内存,不断分配小块 每分配一次,就加入到红黑 ...

  7. JAVA笔记11__File类/File类作业/字节输出流、输入流/字符输出流、输入流/文件复制/转换流

    /** * File类:文件的创建.删除.重命名.得到路径.创建时间等,是唯一与文件本身有关的操作类 */ public class Main { public static void main(St ...

  8. Zabbix webhook 自定义报警媒介

    场景一:使用企业微信机器人报警 图中的token是:在群组中添加机器人,机器人的webhook地址的key var Wechat = { token: null, to: null, message: ...

  9. 理解前端blob和ArrayBuffer,前端接受文件损坏的问题

    1 downloadTemplate().then(res =>{ 2 3 const data = res.data 4 const url = window.URL.createObject ...

  10. CSS px的理解

    px是像素.然而一个屏幕像素的多少是由屏幕的分辨率决定的. 取个极端的栗子:如果分辨率是1w*1w,你设置一个100px宽的输入框,你只占屏幕的1/100,但是如果屏幕的分辨率是100*100,那么你 ...