Milking Grid poj-2185

    题目大意:给出一个字符矩阵,求最小覆盖矩阵(可以残余).

    注释:$1\le R\le 10^5$,$1\le C \le 75$

      想法:和bzoj1355不同的是,bz那题求的是最小覆盖子串。这题其实异曲同工。Discuss中讲的还是蛮清楚的,就是我们对于每一行单独求出Next数组,然后跑出每一行的所有的可能覆盖子串,然后用桶遍历出一个最小值即可。最后的乘积就是答案。

    最后,附上丑陋的代码... ...

#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int maxr=10002;
const int maxc=80;
char GetRead[maxr][maxc];
int row,col;//行和列
int rnext[maxr][maxc];//rnext[i]:对应第i行字符串的next函数
int cnext[maxr];//求纵向的next,每次比较的是整行
int rlen[maxr];//rlen[i]:第i行字符串的最小循环子串的长度
int cnt[maxc];//cnt[i]:统计各宽度出现的次数
int ans_for_col,ans_for_row;//最小覆盖矩阵的宽度和高度
void rgetNext(int r,char*str)//
{
	int k=0;
	rnext[r][1]=0;
	for(int i=1;i<col;i++)
	{
		while(k&&str[k]!=str[i])
			k=rnext[r][k];
		if(str[k]==str[i])
			k++;
		rnext[r][i+1]=k;
	}
	rlen[r]=col-rnext[r][col];
	int i;
	for(i=rlen[r];i<=col;i+=rlen[r])
	{
		cnt[i]++;
	}
	i-=rlen[r];
	for(int j=i+1;j<=col;j++)
	{
		int x=0,y=j;
		while(str[x]==str[y])
		{
			x++;y++;
		}
		if(y==col)
			cnt[j]++;
	}
}
 
void GetNext()
{
	int k=0;
	cnext[1]=0;
	for(int i=1;i<row;i++)
	{
		while(k&& strcmp(GetRead[k],GetRead[i])!=0)
			k=cnext[k];
		if(strcmp(GetRead[k],GetRead[i])==0)
			k++;
		cnext[i+1]=k;
	}
	ans_for_row=row-cnext[row];
}
 
int main()
{
	scanf("%d%d",&row,&col);
	for(int i=0;i<row;i++)
	{
		scanf("%s",GetRead[i]);
	}
	memset(cnt,0,sizeof(cnt));
	for(int i=0;i<row;i++)
	{
		rgetNext(i,GetRead[i]);
	}
	GetNext();
	for(int i=1;i<=col;i++)
	{
		if(cnt[i]==row)
		{
			ans_for_col=i;
			break;
		}
	}
	printf("%d\n",ans_for_col*ans_for_row);
	return 0;
}

 

     小结:挺好的一道题,有意义。网上大部分的题解全都是假的,很多并不极限的数据就能卡死。