HDU - 4333 扩展KMP

题目链接:https://vjudge.net/problem/HDU-4333

题意:

给出一个数字字符串s,问这个字符串的循环同构串中有多少个小于s,多少个等于s,多少个大于s。相同的只算一次。

比如 s=“231”

循环同构串有 231,123,312.

有一个大于s,一个小于s,一个等于s。

题解:

扩展kmp。 

可以发现这个字符串出现循环节才有重复。那么求出最小循环节,算出这个循环节重复了多少次,那么最后的答案除以这个数字。

代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+5;
int nex[maxn],extend[maxn];
char s[maxn];
//预处理计算Next数组
void getNext(char s[]){
    int i=0,j,len=strlen(s);
    nex[0]=len;
    while(s[i]==s[i+1]&&i+1<len) ++i;
    nex[1]=i;
    int p=1;
    for(i=2;i<len;i++){
        if(nex[i-p]+i<nex[p]+p) nex[i]=nex[i-p];
        else {
            j=nex[p]+p-i;
            if(j<0) j=0;
            while(i+j<len&&s[j]==s[j+i]) j++;
            nex[i]=j;
            p=i;
        }
    }
}
//计算extend数组
void EXKMP(char* s1,char* s2){
    int i=0,j,p,len=strlen(s1),len2=strlen(s2);
    getNext(s2);
    while(s1[i]==s2[i]&&i<len2&&i<len) i++;
    extend[0]=i;
    p=0;
    for(i=1;i<len;i++){
        if(nex[i-p]+i<extend[p]+p) extend[i]=nex[i-p];
        else {
            j=extend[p]+p-i;
            if(j<0) j=0;
            while(i+j<len&&j<len2&&s1[j+i]==s2[j]) j++; extend[i]=j;
            p=i;
        }
    }
}
void getnext(char *s){
    int len=strlen(s);
    nex[0]=-1;
    int k=-1,j=0;
    while(j<len){
        if(k==-1||s[k]==s[j]) nex[++j]=++k;
        else k=nex[k];
    }
}
int main(){
    int t;
    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++){
        scanf("%s",s);
        int n=strlen(s);
        for(int i=0;i<n;i++) s[i+n]=s[i];
        n*=2;
        s[n]=0;
        EXKMP(s,s+n/2);
        int a=0,b=0,c=0;
        for(int i=0;i<n/2;i++){
            if(extend[i]>=n/2){
                b++;
            }else{
                if(s[i+extend[i]]>s[extend[i]]) c++;
                else a++;
            }
        }
        getnext(s);
        int t=1;
        int x=n-nex[n];
        if(n%x==0) t=n/2/x;
        printf("Case %d: %d %d %d\n",cas,a/t,b/t,c/t);
    }
    return 0;
}

HDU6629也是扩展kmp的一道题。

HDU6629代码:https://paste.ubuntu.com/p/w7bFrXYZ9z/

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值