博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
bzoj 1414: [ZJOI2009]对称的正方形
阅读量:5094 次
发布时间:2019-06-13

本文共 2838 字,大约阅读时间需要 9 分钟。

我有效率这种东西吗,那是什么,可以吃吗

先对每行每列跑manacher,然后需要求出每个点可以向四周扩展的最大距离,

考虑单独一行,对于每个i只需求出它前面距它最远的一个j满足i-j+1>=min(rad[j]~rad[i])

这个可以用单调队列维护,维护一个rad值单增的单调队列,同时记录队首最后一个被弹出去的元素的位置,就可以维护了。

那么对于每行每列都正反跑一遍然后每个点取min,即每个格子对它上下左右预计能扩展的最大正方形边长取min即可。

需要注意这种整个补了一些奇怪的东西的时候有些格子是没有贡献的,计算答案的时候不考虑它。

//Achen#include
#include
#include
#include
#include
#include
#include
#include
#include
const int N=2007; typedef long long LL;using namespace std;int n,m,a[N][N],mx[N][N],rad1[N][N],rad2[N][N];template
void read(T &x) { T f=1; x=0; char ch=getchar(); while(ch!='-'&&(ch<'0'||ch>'9')) ch=getchar(); if(ch=='-') f=-1,ch=getchar(); for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0'; x*=f;}int tot,tp[N],rad[N],que[N],ql,qr,last;void work(int id,int f) { tot=(f==1?m:n); memset(rad,0,sizeof(rad)); for(int i=1;i<=tot;i++) tp[i]=(f==1?a[id][i]:a[i][id]); for(int i=1,j,k=0;i<=tot;) { while(tp[i-k-1]==tp[i+k+1]) k++; rad[i]=k; for(j=1;j<=k&&rad[i-j]!=rad[i]-j;j++) rad[i+j]=min(rad[i-j],rad[i]-j); k=max(k-j,0); i+=j; } for(int i=1;i<=tot;i++) if(f==1) rad1[id][i]=rad[i]; else rad2[i][id]=rad[i];}void solve(int id,int f) { tot=(f==1?m:n); for(int i=1;i<=tot;i++) if(f==1) rad[i]=rad2[id][i]; else rad[i]=rad1[i][id]; ql=1; qr=0; last=0; for(int i=1;i<=tot;i++) { while(ql<=qr&&rad[que[qr]]>=rad[i]) qr--; que[++qr]=i; while(ql<=qr&&(i-que[ql])+1>rad[que[ql]]) last=que[ql],ql++; int now=0; if(ql<=qr&&(i-que[ql])+1<=rad[que[ql]]) now=min(rad[que[ql]],i-last); if(f==1) mx[id][i]=min(mx[id][i],now); else mx[i][id]=min(mx[i][id],now); } ql=1; qr=0; last=tot+1; for(int i=tot;i>=1;i--) { while(ql<=qr&&rad[que[qr]]>=rad[i]) qr--; que[++qr]=i; while(ql<=qr&&que[ql]-i+1>rad[que[ql]]) last=que[ql],ql++; int now=0; if(ql<=qr&&(que[ql]-i)+1<=rad[que[ql]]) now=min(rad[que[ql]],last-i); if(f==1) mx[id][i]=min(mx[id][i],now); else mx[i][id]=min(mx[i][id],now); }}int main() {#ifdef DEBUG freopen("1.in","r",stdin); freopen("1.out","w",stdout);#endif read(n); read(m); LL ans=n*m; for(int i=1;i<=n;i++) { for(int j=1;j<=2*m+1;j++) a[i*2-1][j]=-1; for(int j=1;j<=m;j++) { a[i*2][j*2-1]=-1; read(a[i*2][j*2]); } a[i*2][m*2+1]=-1; if(i==n) for(int j=1;j<=2*m+1;j++) a[n*2+1][j]=-1; } n=2*n+1; m=2*m+1; memset(mx,127,sizeof(mx)); for(int i=1;i<=n;i++) work(i,1); for(int i=1;i<=m;i++) work(i,-1); for(int i=1;i<=n;i++) solve(i,1); for(int i=1;i<=m;i++) solve(i,-1); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) { if(a[i][j]==-1&&(a[i-1][j]!=-1||a[i][j-1]!=-1)) continue; if(a[i][j]!=-1&&mx[i][j]%2==0) mx[i][j]--; else if(a[i][j]==-1&&mx[i][j]&1) mx[i][j]--; if(mx[i][j]/2) ans+=mx[i][j]/2; } printf("%lld\n",ans); return 0;}/*5 54 2 4 4 4 3 1 4 4 3 3 5 3 3 3 3 1 5 3 3 4 2 1 2 4 */
View Code

 

转载于:https://www.cnblogs.com/Achenchen/p/8322240.html

你可能感兴趣的文章
Plants vs. Zombies(二分好题+思维)
查看>>
依赖包拼合方法
查看>>
professional email address collections
查看>>
jquery兼容IE和火狐下focus()事件
查看>>
玩转spring boot——开篇
查看>>
aix-裸设备文件大小查看
查看>>
ubantu的二三事
查看>>
动图展示16个Sublime Text快捷键用法 ---------------物化的sublime
查看>>
一个简单的 SQLite 的示例
查看>>
3732 Ahui Writes Word
查看>>
POJ 1363 Rails
查看>>
linux下通过phpize为php在不重新编译php情况下安装模块memcache
查看>>
POJ 3259 Wormholes
查看>>
关于公司满意度调查的一点建议
查看>>
考满分软件测试工程师(实习)面试&软达启航面试
查看>>
20130729
查看>>
Petrozavodsk Winter-2018. Carnegie Mellon U Contest
查看>>
nginx 启动报错 “/var/run/nginx/nginx.pid" failed” 解决方法
查看>>
20、自动装配-@Autowired&@Qualifier&@Primary
查看>>
BUG(0):用某位表示特定属性
查看>>