HDU - 3374(最小表示法+最大表示法)

hdu3374
题意:
给你一个字符串,问这个字符串经过移动后的字典序最小的字符串的首字符位置和字典序最大的字符串的首字符的位置,和能出现多少次最小字典序的字符串和最大字典序的字符串
题解:
利用最小表示法与最大表示法O(n)复杂度求出最小字典序和最大字典序串出现位置,然后利用kmp求出next,利用next数组性质求出循环节次数,因为最小和最大字典序串出现次数等于循环节次数(因为有几个循环节,我们就会有几个最小串或最大串的起始点)

#include<bits/stdc++.h>
using namespace std;
const int maxn=2000005;
int nxt[maxn];
char s[maxn];
int n;
int getmin()
{
	int i=0,j=1,k=0;
	while(i<n&&j<n&&k<n){
		int t=s[(i+k)%n]-s[(j+k)%n];
		if(t==0)k++;
		else{
			if(t>0) i=i+k+1;
			else j=j+k+1;
			if(i==j) j++;
			k=0;
		}
	}
	return min(i,j);
}
int getmax()
{
    int i=0,j=1,k=0;
	while(i<n&&j<n&&k<n){
		int t=s[(i+k)%n]-s[(j+k)%n];
		if(t==0) k++;
		else{
			if(t>0)j=j+k+1;
			else i=i+k+1;
			if(i==j)j++;
			k=0;
		}
	}	
	return min(i,j);
} 
void getnxt()//注意:不同的getnext写法要注意区分,否则就会错
{
	int i=0,j=-1;
	nxt[0]=-1;
	while(i<n){
		if(j==-1||s[i]==s[j]){
		    i++;
		    j++;
		    nxt[i]=j;
		}
		else{
			j=nxt[j];
		}
	}
}
void GetNex(){
    memset(nxt,0,sizeof(nxt));
    int j=-1;
    for(int i=0;s[i];i++){
        while(s[i]!=s[j+1]&&j!=-1)j=nxt[j];
        if(s[i]==s[j+1]&&i!=0)j++;
        nxt[i]=j;
    }
}

int main()
{
	while(scanf("%s",s)!=EOF){
         n=strlen(s);
		 int mi=getmin();
		 int mx=getmax();
		 getnxt();
		 int sum=0;
		 if(s[n-1]==s[nxt[n-1]]){
		 	sum=n-(nxt[n-1]+1);
		 }
		 else{
		 	sum=n-(nxt[n-1]);
		 }
		 if(n==1){
		 	printf("1 1 1 1\n");
		 }
		 else{
		 	int ko=1;
		    if(n%sum==0){
		    	ko=n/sum;
			}
			else{
				ko=1;
			}
			printf("%d %d %d %d\n",mi+1,ko,mx+1,ko);
		 }
	}
	return 0;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值