zoukankan      html  css  js  c++  java
  • JZOJ4683. 【GDOI2017模拟8.11】矩阵

    Description

    • 给定一个仅含有大写字母的n*m(n,m<=110)的矩阵,求不同的矩阵个数。

    Solution

    • 考虑枚举按照宽度将矩阵分类,分别统计。
    • 将每一行的每个位置开头,且长度该宽度的字串压一个编号,同一列的该宽度字串上下拼接即可形成任意一个该宽度下的矩阵。
    • 将每一列的编号排列成一个字符串,设为Si
    • 将所有列的S排列成:S1#S2#S3#…Sk
    • 我们只需要用后缀自动机求出这个大的字符串(字符域取决于你的编号的多少)中的不同字串个数就好了。

    Q&A

    • 为什么要将每一列的S连起来而不分开求?因为这个宽度下的矩阵是一类的,有重复的情况要计算到。
    • 怎么压编号?也许你可以哈希(双哈希,用单哈希会爆),但我用的是trie,空间复杂度就很大了。
    • 有#的后缀自动机怎么求其中不同字串个数(‘S1#’ = 'S2#'算重)?用自动机的边构成的DAG做DP时,判断一下是不是#,如果是的话就不要转移,这样就能保证计算到的字符串没有#

    PS

    • 第一次打后缀自动机常数巨大QAQ。
    #pragma GCC optimize(2)
    #include<cstdio>
    #include<cmath>
    #include<cstring>
    #include<algorithm>
    #include<map>
    #define maxn 111
    #define maxm 30000
    #define maxp 1000005
    #define ll long long 
    using namespace std;
    
    int n,m,i,j,k,l,tot,a[maxn][maxn],nm[maxn][maxn][maxn];
    int x,y,tr[maxp][27],sz,bz[maxp];
    int du[maxm],t,w,d[maxm],f[maxm];
    char ch;
    ll ans;
    
    int rt=1,las,num,fa[maxm],len[maxm];
    map<int,int> to[maxm];
    map<int,int>::iterator it;
    void add(int c){
    	int p=las,np=las=++num; to[np].clear();
    	len[np]=len[p]+1;
    	for(;p&&!to[p][c];p=fa[p]) 
    		to[p][c]=np;
    	if (!p) fa[np]=rt; else {
    		int q=to[p][c];
    		if (len[q]==len[p]+1) fa[np]=q; else {
    			int nq=++num; to[nq].clear();
    			len[nq]=len[p]+1;
    			fa[nq]=fa[q],fa[q]=fa[np]=nq;
    			to[nq]=to[q];
    			for(;p&&to[p][c]==q;p=fa[p]) to[p][c]=nq;
    		}
    	}
    }
    
    void tropu(){	
    	for(i=1;i<=num;i++) 
    		for(it=to[i].begin();it!=to[i].end();it++)
    			du[it->second]++;
    	memset(f,0,sizeof(f));
    	t=0,w=1,d[1]=1,f[1]=1;
    	while (t<w){
    		x=d[++t];
    		for(it=to[x].begin();it!=to[x].end();it++) 	{
    			y=it->second;
    			du[y]--;
    			if (!du[y]) d[++w]=y;
    			if (it->first) f[y]+=f[x];
    		}
    	}
    	for(i=2;i<=num;i++) ans+=f[i];
    }
    
    int main(){
    	freopen("matrix9.in","r",stdin);
    	scanf("%d%d",&n,&m); 
    	for(i=1;i<=n;i++) for(j=1;j<=m;j++) {
    		for(ch=getchar();ch<'A'||ch>'Z';ch=getchar());
    		a[i][j]=ch-'A'+1;
    	}
    	
    	tot=1;
    	for(i=1;i<=n;i++){
    		for(j=1;j<=m;j++) {
    			x=1;
    			for(k=j;k<=m;k++) {
    				if (!tr[x][a[i][k]]) tr[x][a[i][k]]=++tot;
    				x=tr[x][a[i][k]];
    				nm[i][j][k]=x;
    			}
    		}
    	}
    	
    	for(l=0;l<m;l++) {
    		sz=0,num=1,las=rt; to[rt].clear();
    		for(j=1;j+l<=m;j++) {
    			for(i=1;i<=n;i++) {
    				if (!bz[nm[i][j][j+l]])
    					bz[nm[i][j][j+l]]=++sz;
    				add(bz[nm[i][j][j+l]]);
    			}
    			add(0);
    		}
    		tropu();
    	}
    	printf("%lld",ans);
    }
    
  • 相关阅读:
    visual studio 2013 中配置OpenCV2.4.13 姿势
    全栈技能图谱
    Lua 基础
    Lua手动编译姿势
    字符串专题:几种奇怪的算法
    字符串专题:KMP POJ 3561
    字符串专题:后缀数组
    字符串专题:map POJ 1002
    2015安徽省赛 G.你来擒孟获
    求方程解问题
  • 原文地址:https://www.cnblogs.com/DeepThinking/p/11700943.html
Copyright © 2011-2022 走看看