正题

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


题目大意

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

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

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


解题思路

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

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

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

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

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


code

#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#define ull unsigned long long
#define lowbit(x) (x&-x)
using namespace std;
const ll N=1e6+10;
const ull g=131;
ll n,m,t[N],ac[N],cr[N],dp[N],lim;
ull h[N],f[N],pw[N];
char c[N],*s[N];
void Change(ll x,ll val){
while(x<=lim){
t[x]+=val;
x+=lowbit(x);
}
return;
}
ll Ask(ll x){
ll ans=0;
while(x){
ans+=t[x];
x-=lowbit(x);
}
return ans;
}
ll Query(ll l,ll r)
{return Ask(r)-Ask(l-1);}
ull geth(ll l,ll r)
{return h[r]-h[l-1]*pw[r-l+1];}
ull getf(ll l,ll r)
{return f[l]-f[r+1]*pw[r-l+1];}
signed main()
{
freopen("paper.in","r",stdin);
freopen("paper.out","w",stdout);
scanf("%lld%lld",&n,&m);pw[0]=1;
for(ll i=1;i<=max(n,m);i++)
pw[i]=pw[i-1]*g;
memset(ac,0x3f,sizeof(ac));
memset(cr,0x3f,sizeof(cr));
s[1]=c-1;
for(ll p=1;p<=n;p++){
scanf("%s",s[p]+1);
for(ll i=1;i<=m;i++)
h[i]=h[i-1]*g+s[p][i]-'a';
for(ll i=m;i>=1;i--)
f[i]=f[i+1]*g+s[p][i]-'a';
for(ll i=2;i<=m;i++){
ll l=0,r=min(i-2,m-i);
while(l<=r){
ll mid=(l+r)>>1;
if(geth(i-mid-1,i-1)==getf(i,i+mid))l=mid+1;
else r=mid-1;
}
ac[i]=min(ac[i],r);
}
s[p+1]=s[p]+m;
}
f[n+1]=0;
for(ll p=1;p<=m;p++){
for(ll i=1;i<=n;i++)
h[i]=h[i-1]*g+s[i][p]-'a';
for(ll i=n;i>=1;i--)
f[i]=f[i+1]*g+s[i][p]-'a';
for(ll i=2;i<=n;i++){
ll l=0,r=min(i-2,n-i);
while(l<=r){
ll mid=(l+r)>>1;
if(geth(i-mid-1,i-1)==getf(i,i+mid))l=mid+1;
else r=mid-1;
}
cr[i]=min(cr[i],r);
}
}
lim=m;Change(1,1);dp[1]=1;
for(ll i=2;i<=m;i++){
bool tmp=(Query(i-ac[i]-1,i-1)!=0);
dp[i]=dp[i-1]+tmp;
if(tmp)Change(i,1);
} memset(t,0,sizeof(t));
Change(m,1);ll sum=dp[m];
for(ll i=m-1;i>=1;i--){
bool tmp=(Query(i+1,i+ac[i+1]+1)!=0);
if(tmp)sum+=dp[i],Change(i,1);
} memset(t,0,sizeof(t));
lim=n;Change(1,1);
for(ll i=2;i<=n;i++){
bool tmp=(Query(i-cr[i]-1,i-1)!=0);
dp[i]=dp[i-1]+tmp;
if(tmp)Change(i,1);
} memset(t,0,sizeof(t));
Change(n,1);ll ans=dp[n];
for(ll i=n-1;i>=1;i--){
bool tmp=(Query(i+1,i+cr[i+1]+1)!=0);
if(tmp)ans+=dp[i],Change(i,1);
}
printf("%lld\n",ans*sum);
return 0;
}

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. SpringCloud之Hystrix集群监控turbine仪表盘

    1.引入 在前一节中我们演示了单机模式下Hystrix服务监控Dashboard仪表盘,但是在实际生产中微服务都是集群模式, 为了更接近世界生产,我们在这里也给大家讲一下如何监控集群模式 2.准备工作 ...

  2. WPF以鼠标当前位置进行缩放

    <Window x:Class="ImageViewer.MainWindow" xmlns="http://schemas.microsoft.com/winfx ...

  3. Springboot中配置druid

    pom文件信息: <!--引入druid数据源--> <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> ...

  4. Ztree 树插件 树节点名称太长的解决方案

    样式允许的情况下 给背景div加滚动条.. 或者使用省略号方法:使用addDiyDom   http://blog.csdn.net/zhengbo0/article/details/17759543 ...

  5. Python创建二维列表的正确姿势

    Python创建二维列表的正确姿势 简介 Python中没有数组,使用list结构代替,并且list结构的功能更加强大: 支持动态扩容,无需担心元素过量 对list内的元素类型不做一致性约束 提供丰富 ...

  6. js函数和封装

    $就是jquery对象,$()就是jQuery(),在里面可以传参数,作用就是获取元素 js对象与jQuery对象的区别:jQuery对象是一个数组,jQuery对象转为js对象:[0] 取第一个即可 ...

  7. HTML5存储 ——Web Storage(localStorage 和 sessionStorage)

    一.localStorage对象临时储存API 方法: 1.localStorage.setItem(key,value)---设置存储内容 2.localStorage.getItem(key)-- ...

  8. 手写 lodash/get、lodash/set 方法

    动机:平时写js代码时经常遇到要使用 lodash 中 _.get 和 _.set 的情况,每次使用都要引用 lodash,总感觉很烦,能不能自己实现一个简单的方法来实现一样的功能呢? get 方法实 ...

  9. 在node节点部署kubectl管理k8s集群

    感谢!原文链接:https://blog.csdn.net/sinat_35930259/article/details/79994078 kubectl是k8s的客户端程序,也是k8s的命令行工具, ...

  10. git02

    Git Gui的使用 Ssh key 介绍及使用 Ssh key介绍 我理解的就是每台电脑上会产生出一个ssh key,然后自己有一个远程账户,但是自己有可能有很多台电脑, 包括家里的电脑还有公司的电 ...