zoukankan      html  css  js  c++  java
  • POJ 2185 Milking Grid--另一种字符串的循环节

    在Power String中,求一个字符串的循环节,应满足L mod (L-next[L])=0,则循环节长度为L-next[L]。

    这个找next[L]的可以用hash。

    #include<bits/stdc++.h>
    using namespace std;
    typedef unsigned long long ull;
    char a[2000000];
    int len=0;
    ull sum[2000000],power[2000000];
    ull get(int l,int r)
    {
        return sum[r]-sum[l-1]*power[r-l+1];
    }
    int main()
    {
    	while(true)
    	{
    		scanf("%s",a+1);
    		len=strlen(a+1);
    		if(a[1]=='.'&&len==1)break;
    		memset(sum,0,sizeof(sum));
    		memset(power,0,sizeof(power));
    		for(int i=1;i<=len;i++)
    		     sum[i]=sum[i-1]*193+ull(a[i])+1;
    		power[0]=1;
    		for(int i=1;i<=len;i++)
    		     power[i]=power[i-1]*193;
    		for(int i=1;i<=len;i++) //暴力枚举循环节的长度
    		{
    			if(len%i!=0)continue;
    			else
    			{
    				ull a1=get(1,len-i),a2=get(i+1,len); //注意是取长度为len-i的前缀,看是否等于长度为len-i的后缀
    				if(a1==a2)
    				{
    					printf("%d
    ",len/i);//得到循环节的个数
    					break;
    				}
    			}
    		} 
    	}
    
    	return 0;
    }
    

      也可以用Kmp算法

    #include<bits/stdc++.h>
    #define int long long
    #define N 1000005
    using namespace std;
    char s2[N];
    int p[N],m;
    void pre()  //求next数组 
    {
        memset(p,0,sizeof p);
        for(int i=1,j=0;i<m;i++)
    	{
            while(j>0&&s2[j+1]!=s2[i+1])j=p[j];
            if(s2[i+1]==s2[j+1])j++;
            p[i+1]=j;
        }
    }
    signed main(){
        while(~scanf("%s",s2+1))
    	{
            if(s2[1]=='.')break;
            m=strlen(s2+1);
            pre();
            if(m%(m-p[m])) //如果取模不0的话,则没有循环节 
    		    puts("1");
            else 
    		     printf("%lld
    ",m/(m-p[m]));
        }
        return 0;
    }
    

      

    存在另一种形式的循环节,例如abcabca,此时如果将abc重写三次,得到abcabcabc,则原字符串为其前缀.

    此时对于原字符串,其循环节长度为L-next[L]=7-4=3,循环节为abc.,不需要满足L mod (L-next[L])=0这个条件

    证明如下:设abcabcab为s1s2....s8

    因为next[8]=5,于是s[1..5]=s[4..8]于是s[1..3]=s[4..6]

    原字符串:     s1 s2 s3 s4 s5 s6 s7 s8

    循环节构成  s1 s2 s3 s1 s2 s3 s1 s2 s3

    蓝色那一段已相等了。

    由上图可知s[1..2]=s[4..5],

    而s[7..8]=s[4..5],于是s[1..2]=s[7..8],于是品红色那一段也相等了。

    具体可见下面这个题

    [Baltic2009]Radio Transmission

    给你一个字符串,它是由某个字符串不断自我连接形成的。 但是这个字符串是不确定的,现在只想知道它的最短长度是多少.
    Input

    第一行给出字符串的长度,1 < L ≤ 1,000,000. 第二行给出一个字符串,全由小写字母组成.
    Output

    输出最短的长度
    Sample Input

    8

    cabcabca
    Sample Output

    3
    HINT

    对于样例,我们可以利用"cab"不断自我连接得到"cabcabcab",读入的cabcabca,是它的子串

    https://blog.csdn.net/weixin_30767835/article/details/96359998?depth_1-utm_source=distribute.pc_relevant.none-task&utm_source=distribute.pc_relevant.none-task

    #include <cstdio>
     
    #define MAXN 1000002
     
    using namespace std;
     
    char s[MAXN];
    int next[MAXN];
    int n;
     
    void solve()
    {
        next[1] = 0;
        int j = 0;
        for (int i = 2; i <= n; i ++)
        {
            while ((j) && (s[j + 1] != s[i])) j = next[j];
            if (s[j + 1] == s[i]) j ++;
            next[i] = j;
        }
        printf("%d
    ", n - next[n]);
    }
     
    int main()
    {
        scanf("%d
    %s", &n, s + 1);
        solve();
        return 0;
    }
    

      

    对于Milking Gird

    Sol:

    将大矩阵的每一列看成一个字符,然后对该大矩阵的每一列求出next[i],则列最短循环节长度=小矩阵的宽=ans1=c-next[c]。        

    将大矩阵的每一行看成一个字符,然后对该大矩阵的每一行求出next[j],则行最短循环节长度=小矩阵的高=ans2=r-next[r]。        

    最后答案:ans1*ans2即为所求矩阵的面积。

    #include<bits/stdc++.h>
    using namespace std;
    char s[10010][100];
    int next[10010];
    int r,c;
    bool str1(int i,int j)//判断第i行和第j行是否相等
    {
        for(int k=0;k<c;k++)
            if(s[i][k]!=s[j][k])
                return false;
        return true;
    }
    bool str2(int i,int j)//判断第i列和第j列是否相等
    {
        for(int k=0;k<r;k++)
            if(s[k][i]!=s[k][j])
                return false;
        return true;
    }
    int main()
    {
        while(scanf("%d%d",&r,&c)==2)
        {
            for(int i=0;i<r;i++)
                scanf("%s",s[i]);
            next[0]=next[1]=0;
            for(int i=1;i<r;i++)//把每行看成一个字符
            {
                int j=next[i];
                while(j && str1(i,j)==false) j=next[j];
                next[i+1] = (str1(i,j)==true)? j+1 :0;
            }
         
            int ans1=r-next[r];
            next[0]=next[1]=0;
            for(int i=1;i<c;i++)//把每列看成一个字符
            {
                int j=next[i];
                while(j && str2(i,j)==false) j=next[j];
                next[i+1] = (str2(i,j)==true)? j+1 :0;
            }
            int ans2=c-next[c];
         
            printf("%d
    ",ans1*ans2);
        }
    }
    //原文链接:https://blog.csdn.net/u013480600/article/details/22990715
  • 相关阅读:
    源码分析:①ReentrantLock之公平锁和非公平锁
    源码分析:同步基础框架——AbstractQueuedSynchronizer(AQS)
    java 同步锁:synchronized 关键字
    Java 中的锁优化
    Java 魔法类:Unsafe 解析
    实战:SpringBoot 2.3.0新特性之优雅停机
    实战:windows下使用docker部署springboot web demo项目
    版本控制SVN的使用笔记
    Maven项目管理:SpringMVC+Mybatis+Velocity整合笔记
    java常用集合总结
  • 原文地址:https://www.cnblogs.com/cutemush/p/12301822.html
Copyright © 2011-2022 走看看