zoukankan      html  css  js  c++  java
  • POJ2406 Power Strings POJ1961 Period

    http://poj.org/problem?id=2406
    http://poj.org/problem?id=1961
    几乎是一个题

    1961是对于第 (i) 位,求 ([1,i]) 能不能由一段字符循环一次以上组成,输出 (i) 和这样的长度最小的循环节循环次数
    2406是只对第 (n) 位输出最小长度循环节循环次数


    kmp,考虑 kmp 的 (fail) 数组,(fail_i) 表示的是如果 (i) 失配,那么要从哪一位开始继续匹配
    更本质的,他是 ([1,i]) 中,最长的前缀等于后缀的长度
    例如 (fail_i=m),那么字串 ([1,m]=[i-m+1,i]),如果这两个区间的并集等于整个区间,那么 (i-fail_i)可能 是这个区间的循环节长度
    因为并集等于整个区间,所以 (forall 1le j le fail_i,s(j)=s(j+i-fail_i))
    对于这个式子也可以理解为前缀向后移动了 (i-fail_i) 位得到了后缀,所以相当于每一个区间内字符都与向后移动 (i-fail_i) 位的字符相同

    因此,只要 (i mod i-fail_i=0),就说明了 (i-fail_i)([1,i]) 最小循环节长度(这也是为什么刚才说可能)

    POJ2406

    char s[6000005];
    int fail[6000005];
    int main(){
    	scanf("%s",s+1);
    	while(s[1]!='.'){
    		int n=std::strlen(s+1);
    		fail[1]=0;
    		for(reg int j,i=2;i<=n;i++){
    			j=fail[i-1];
    			while(j&&s[j+1]!=s[i]) j=fail[j];
    			if(j) fail[i]=j+1;
    			else fail[i]=(s[1]==s[i]);
    		}
    		printf("%d
    ",(n%(n-fail[n]))?1:(n/(n-fail[n])));
    		scanf("%s",s+1);
    	}
    	return 0;
    }
    

    POJ1961

    char s[6000005];
    int fail[6000005];
    int n;
    int main(){
    	scanf("%d",&n);
    	int T=0;
    	while(n){
    		scanf("%s",s+1);
    		fail[1]=0;
    		for(reg int j,i=2;i<=n;i++){
    			j=fail[i-1];
    			while(j&&s[j+1]!=s[i]) j=fail[j];
    			if(j) fail[i]=j+1;
    			else fail[i]=(s[1]==s[i]);
    		}
    		printf("Test case #%d
    ",++T);
    		for(reg int i=2;i<=n;i++)
    			if(!(i%(i-fail[i]))&&i/(i-fail[i])>1) printf("%d %d
    ",i,i/(i-fail[i]));
    		EN;
    		scanf("%d",&n);
    	}
    	return 0;
    }
    
  • 相关阅读:
    数据结构
    ADC
    SPI
    定时器原理
    IO中断
    恩智浦样片申请
    UART
    随机生成数字验证码
    判断网络是否连接Internet
    清理SQL数据库日志
  • 原文地址:https://www.cnblogs.com/suxxsfe/p/13329179.html
Copyright © 2011-2022 走看看