zr#955 折纸

分析

我们发现行列独立

只要分别求出答案然后相乘即可

而对于所有行我们可以将其哈希后变为一行

这样就转化为了1*n的问题

 代码

#include<bits/stdc++.h>
using namespace std;
const int mod = 1e9+7;
const int H = 233;
string s[100100];
int a[100100],b[100100],pre[100100],sur[100100],p[100100],d[300100];
inline void getman(int a[],int n){
    int i,j,k,id=0,mx=1;
    for(i=1;i<=n;i++)d[i*2]=a[i],d[i*2+1]=-1;
    d[1]=-1,d[0]=-123,d[2*n+2]=-456;
    p[0]=1;
    for(i=1;i<=2*n+2;i++){
      p[i]=i<mx?min(p[2*id-i],mx-i):1;
      while(d[i-p[i]]==d[i+p[i]])p[i]++;
      if(i+p[i]>mx)id=i,mx=i+p[i];
    }
    for(i=1;i<=n;i++)p[i]=p[i*2+1]/2;
}
inline int work(int a[],int n){
    int i,j,k,ans=0;
    memset(pre,0,sizeof(pre));
    memset(sur,0,sizeof(sur));
    memset(p,0,sizeof(p));
    getman(a,n);
    k=0;
    for(i=1;i<n;i++)if(i-p[i]<=k)k=i,pre[i]=1;
    k=n;
    for(i=n-1;i>0;i--)if(i+p[i]>=k)k=i,sur[i]=1;
    k=1;
    for(i=1;i<n;i++){
      if(sur[i])ans+=k;
      if(pre[i])k++;
    }
    ans+=k;
    return ans;
}
int main(){
    int n,m,i,j,k;
    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)cin>>s[i];
    for(i=1;i<=n;i++)
      for(j=m;j>0;j--)s[i][j]=s[i][j-1];
    for(i=1;i<=n;i++){
      for(j=1;j<=m;j++)a[i]=(1ll*a[i]*H%mod+(s[i][j]-'a'))%mod;
    }
    for(i=1;i<=m;i++){
      for(j=1;j<=n;j++)b[i]=(1ll*b[i]*H%mod+(s[j][i]-'a'))%mod;
    }
    printf("%lld\n",1ll*work(a,n)*work(b,m));
    return 0;
}

 

posted @ 2019-09-06 08:27  水题收割者  阅读(172)  评论(0编辑  收藏  举报