正题

题目链接: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. 经典树与图论(最小生成树、哈夫曼树、最短路径问题---Dijkstra算法)

    参考网址: https://www.jianshu.com/p/cb5af6b5096d 算法导论--最小生成树 最小生成树:在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树. im ...

  2. Ubuntu 16.04 LTS 64位系统 安装Docker

    本文开发环境为Ubuntu 16.04 LTS 64位系统,通过apt的docker官方源安装最新的Docker CE(Community Edition),即Docker社区版,是开发人员和小型团队 ...

  3. java中的静态内部类

    静态内部类是 static 修饰的内部类,这种内部类的特点是: 1. 静态内部类不能直接访问外部类的非静态成员,但可以通过 new 外部类().成员 的方式访问 2. 如果外部类的静态成员与内部类的成 ...

  4. java字符串(String和StringBuilder)

    1.String 1.1.创建String对象的方法(三种方式) String s1 = "zhang"; 创建一个字符串对象zhang,名为s1 String s2 = new ...

  5. JAVA简单精确计算工具类

    1 public class ArithUtil { 2 3 // 默认除法运算精度 4 private static final int DEF_DIV_SCALE = 10; 5 6 privat ...

  6. vue3.0入门(三)

    前言 最近在b站上学习了飞哥的vue教程 学习案例已上传,下载地址 class绑定 对象绑定 :class='{active:isActive}' // 相当于class="active&q ...

  7. group by分组查询

    有如下数据: 一个简单的分组查询的案例 按照部门编号deptno分组,统计每个部门的平均工资. select deptno,avg(sal) avgs from emp group by deptno ...

  8. vue 引用 tcplayer 做直播( 俩个例子,都可以用。替换直播地址即可,后端推流,前端观看。 )

    例子一比例子二更加容易被理解.另外 m3u8 也支持 webrtc 开头的直播地址. 补充JS 得下载到本地,自行引入: https://imgcache.qq.com/open/qcloud/liv ...

  9. 通俗易懂讲解Word2vec的本质

    本文首发于微信公众号「对白的算法屋」,来一起学AI叭 一.Word2vec CBOW(Continuous Bag-of-Words):每个词的含义都由相邻词决定. Skip-gram:依据分布的相似 ...

  10. Dockerfile简介及基于centos7的jdk镜像制作

    Dockerfile简介 dockerfile 是一个文本格式的配置文件, 用户可以使用 Dockerfile 来快速创建自定义的镜像, 另外,使用Dockerfile去构建镜像好比使用pom去构建m ...