Milking Grid POJ - 2185(kmp判断循环节)

题意:传送门
题解:首先需要了解对于一个字符串的循环节的求法,如果是完美的,也就是 i % ( i − N e x t [ i ] ) = = 0 i\%(i-Next[i])==0 i%(iNext[i])==0的情况,那么最小的循环节就是 i − N e x t [ i ] i-Next[i] iNext[i],其他的循环节就是它的倍数了,如果是不完美的,那么最小循环节也是 i − N e x t [ i ] i-Next[i] iNext[i],只不过是之后循环节不一定是它的倍数了,比如 a a a b a a aaabaa aaabaa,算出的 i − N e x t [ i ] = = 2 i-Next[i]==2 iNext[i]==2,循环节就是 4 4 4,但是 5 , 6 5,6 5,6也可以,不一定是倍数了,所以对于每行的循环节长度求出来是没有意义的,何况行数只有 75 75 75的数据范围,直接可以暴力,不行可以hash,之后算出最小的宽度后,可以对于行数直接使用 k m p kmp kmp,直接可以将对应的循环节看成一个字符,然后行就是一串字符串了,之后求出 n − N e x t [ n ] n-Next[n] nNext[n]就是最小的长度了,但是有时候宽度边长后,对应的长度是否会变短呢?这个是不可能的,如果宽度变长,对应的行数上字符比较就会越来越多,长度只会变得越来越长,只会使得情况越来越糟糕,所以暴力枚举出宽度,长度使用 k m p kmp kmp线性求出,最后相乘就是答案了。
c o d e : code: code:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=1e4+5,M=80;
char str[N][M];
int n,m,Next[N];
bool st[M];
int main()
{
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        cin>>str[i];
        for(int j=1;j<=m;j++){
            bool is_match=true;
            for(int k=j;k<m;k+=j){
                for(int u=0;u<j&&k+u<m;u++){
                    if(str[i][u]!=str[i][k+u]){
                        is_match=false;
                        break;
                    }
                }
                if(!is_match)break;
            }
            if(!is_match)st[j]=true;
        }
    }
    int width;
    for(int i=1;i<=m;i++){
        if(!st[i]){
            width=i;
            break;
        }
    }
    for(int i=1;i<=n;i++)str[i][width]=0;
    for(int i=2,j=0;i<=n;i++){
        while(j&&strcmp(str[i],str[j+1]))j=Next[j];
        if(!strcmp(str[i],str[j+1]))j++;
        Next[i]=j;
    }
    int height=n-Next[n];
    cout<<width*height<<endl;
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值