正题

题目链接:https://www.ybtoj.com.cn/problem/526


题目大意

一个\(n\times m\)的网格上有字母,你每次可以沿平行坐标轴对折网格,要求对折的对应位置字母相同。

询问有多少个可能对折出来的子矩阵。

\(1\leq n\times m\leq 10^6\)


解题思路

首先行和列是独立的,行的对折不会和列的对折有任何关联,所以可以分开考虑行和列可以对折出的区间。

然后设每一行分开对每个轴求出一个最大对折距离(这个用二分+\(hash\)或者马拉车就可以求出来了),然后同位置的所有行取最小值就好了。

之后对于每个轴的位置就有一个可以转移过来的区间,而且左右的对折如果过头了不会影响答案(可以自己画个图,因为回文串的性质,那么两边一定可以先对折出一个更小不会冲突的区间)

维护一个前缀和就好了(考场上犯病写了个树状数组)

时间复杂度\(O(n\log n)\)


code

  1. #include<cstdio>
  2. #include<cstring>
  3. #include<algorithm>
  4. #define ll long long
  5. #define ull unsigned long long
  6. #define lowbit(x) (x&-x)
  7. using namespace std;
  8. const ll N=1e6+10;
  9. const ull g=131;
  10. ll n,m,t[N],ac[N],cr[N],dp[N],lim;
  11. ull h[N],f[N],pw[N];
  12. char c[N],*s[N];
  13. void Change(ll x,ll val){
  14. while(x<=lim){
  15. t[x]+=val;
  16. x+=lowbit(x);
  17. }
  18. return;
  19. }
  20. ll Ask(ll x){
  21. ll ans=0;
  22. while(x){
  23. ans+=t[x];
  24. x-=lowbit(x);
  25. }
  26. return ans;
  27. }
  28. ll Query(ll l,ll r)
  29. {return Ask(r)-Ask(l-1);}
  30. ull geth(ll l,ll r)
  31. {return h[r]-h[l-1]*pw[r-l+1];}
  32. ull getf(ll l,ll r)
  33. {return f[l]-f[r+1]*pw[r-l+1];}
  34. signed main()
  35. {
  36. freopen("paper.in","r",stdin);
  37. freopen("paper.out","w",stdout);
  38. scanf("%lld%lld",&n,&m);pw[0]=1;
  39. for(ll i=1;i<=max(n,m);i++)
  40. pw[i]=pw[i-1]*g;
  41. memset(ac,0x3f,sizeof(ac));
  42. memset(cr,0x3f,sizeof(cr));
  43. s[1]=c-1;
  44. for(ll p=1;p<=n;p++){
  45. scanf("%s",s[p]+1);
  46. for(ll i=1;i<=m;i++)
  47. h[i]=h[i-1]*g+s[p][i]-'a';
  48. for(ll i=m;i>=1;i--)
  49. f[i]=f[i+1]*g+s[p][i]-'a';
  50. for(ll i=2;i<=m;i++){
  51. ll l=0,r=min(i-2,m-i);
  52. while(l<=r){
  53. ll mid=(l+r)>>1;
  54. if(geth(i-mid-1,i-1)==getf(i,i+mid))l=mid+1;
  55. else r=mid-1;
  56. }
  57. ac[i]=min(ac[i],r);
  58. }
  59. s[p+1]=s[p]+m;
  60. }
  61. f[n+1]=0;
  62. for(ll p=1;p<=m;p++){
  63. for(ll i=1;i<=n;i++)
  64. h[i]=h[i-1]*g+s[i][p]-'a';
  65. for(ll i=n;i>=1;i--)
  66. f[i]=f[i+1]*g+s[i][p]-'a';
  67. for(ll i=2;i<=n;i++){
  68. ll l=0,r=min(i-2,n-i);
  69. while(l<=r){
  70. ll mid=(l+r)>>1;
  71. if(geth(i-mid-1,i-1)==getf(i,i+mid))l=mid+1;
  72. else r=mid-1;
  73. }
  74. cr[i]=min(cr[i],r);
  75. }
  76. }
  77. lim=m;Change(1,1);dp[1]=1;
  78. for(ll i=2;i<=m;i++){
  79. bool tmp=(Query(i-ac[i]-1,i-1)!=0);
  80. dp[i]=dp[i-1]+tmp;
  81. if(tmp)Change(i,1);
  82. }
  83. memset(t,0,sizeof(t));
  84. Change(m,1);ll sum=dp[m];
  85. for(ll i=m-1;i>=1;i--){
  86. bool tmp=(Query(i+1,i+ac[i+1]+1)!=0);
  87. if(tmp)sum+=dp[i],Change(i,1);
  88. }
  89. memset(t,0,sizeof(t));
  90. lim=n;Change(1,1);
  91. for(ll i=2;i<=n;i++){
  92. bool tmp=(Query(i-cr[i]-1,i-1)!=0);
  93. dp[i]=dp[i-1]+tmp;
  94. if(tmp)Change(i,1);
  95. }
  96. memset(t,0,sizeof(t));
  97. Change(n,1);ll ans=dp[n];
  98. for(ll i=n-1;i>=1;i--){
  99. bool tmp=(Query(i+1,i+cr[i+1]+1)!=0);
  100. if(tmp)ans+=dp[i],Change(i,1);
  101. }
  102. printf("%lld\n",ans*sum);
  103. return 0;
  104. }

YbtOJ#526-折纸游戏【二分,hash】的更多相关文章

  1. 【bzoj3796】Mushroom追妹纸 Kmp+二分+Hash

    题目描述 给出字符串s1.s2.s3,找出一个字符串w,满足: 1.w是s1的子串: 2.w是s2的子串: 3.s3不是w的子串. 4.w的长度应尽可能大 求w的最大长度. 输入 输入有三行,第一行为 ...

  2. Solution -「LOCAL」「cov. HDU 6816」折纸游戏

    \(\mathcal{Description}\)   Link(削弱版).   \(n\) 张纸叠在一起对折 \(k\) 次,然后从上到下为每层的正反两面写上数字,求把纸重新摊平后每张纸上的数字序列 ...

  3. CSS3写折纸

    <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type" content ...

  4. BZOJ 1014: [JSOI2008]火星人prefix [splay 二分+hash] 【未完】

    1014: [JSOI2008]火星人prefix Time Limit: 10 Sec  Memory Limit: 162 MBSubmit: 6243  Solved: 2007[Submit] ...

  5. 折纸问题java实现

    /** * 折纸问题 这段代码写的太low了 本人水平有限 哎... 全是字符串了 * @param n * @return * @date 2016-10-7 * @author shaobn */ ...

  6. 【BZOJ】1074: [SCOI2007]折纸origami

    http://www.lydsy.com/JudgeOnline/problem.php?id=1074 题意:一开始有一个左上角是(0,100),右下角是(100,0)的纸片,现在可以沿有向直线折n ...

  7. 1074: [SCOI2007]折纸origami - BZOJ

    Description 桌上有一张边界平行于坐标轴的正方形纸片,左下角的坐标为(0,0),右上角的坐标为(100,100).接下来执行n条折纸命令.每条命令用两个不同点P1(x1,y1)和P2(x2, ...

  8. CSS3实现文字折纸效果

    CSS3实现文字折纸效果 效果图: 代码如下,复制即可使用: <!DOCTYPE html> <html> <head> <title></tit ...

  9. BZOJ1014: [JSOI2008]火星人prefix(splay 二分 hash)

    题意 题目链接 Sol 一眼splay + 二分hash,不过区间splay怎么写来着呀 试着写了两个小时发现死活不对 看了一下yyb的代码发现自己根本就不会splay.... // luogu-ju ...

随机推荐

  1. docker commit (从容器创建一个新的镜像)

    从容器创建一个新的镜像 docker commit [OPTIONS] CONTAINER [REPOSITORY[:TAG]] -a :提交的镜像作者: -c :使用Dockerfile指令来创建镜 ...

  2. asp.net core 常见知识点

  3. C# volatile 的使用

    class Program { private static volatile bool bChanged; static void Main(string[] args) { Thread t1 = ...

  4. 13.SpringMVC之全局异常

    我们知道,系统中异常包括:编译时异常和运行时异常RuntimeException,前者通过捕获异常从而获取异常信息,后者主要通过规范代码开发.测试通过手段减少运行时异常的发生.在开发中,不管是dao层 ...

  5. python创建字典多种方式

    1.创建空字典 >>> dic = {} >>> type(dic) <type 'dict'> 2.直接赋值创建 >>> dic = ...

  6. Redis常用技术

    Xml配置: <?xml version='1.0' encoding='UTF-8' ?> <!-- was: <?xml version="1.0" e ...

  7. 多线程Synchronized的两种锁

    Synchronized的作用: 能够保证在同一时刻最多只有一个线程执行该段代码,以达到保证并发安全的效果 Synchronized的两个用法: 1)对象锁 包括方法锁(默认锁对象为this当前实例对 ...

  8. Spring Boot +Vue 项目实战笔记(二):前后端结合测试(登录页面开发)

    前言:关于开发环境 每位 Coder 都有自己偏好的开发工具,从大的方面划分主要有文本编辑器流和 IDE 流两种,我有一段时间也喜欢用编辑器(Sublime Text.Vim),但对我来说开发效率确实 ...

  9. Learning ROS: Aboat URDF (Unified Robot Description Format)

    Building a Visual Robot Model with URDF from Scratch roscore &# With $(find urdf_tutorial), this ...

  10. Learning ROS: Getting started with roswtf (检查ROS系统,找出问题)

    本文主要部分来源于ROS官网的Tutorials. roswtf是ROS的检查工具,用于检查ROS安装和运行系统. Checking your installation&Offline mak ...