HDU 3374 exkmp+字符串最大最小表示法

题意

找到一个字符串中最先出现的最小(大)表示位置,和最小(大)表示串出现次数

分析

用最小(大)表示法求出最先出现的最小(大)表示位置,然后将串长扩两倍用exkmp找出现次数。

Code

#include<bits/stdc++.h>
#define fi first
#define se second
#define lson l,mid,p<<1
#define rson mid+1,r,p<<1|1
#define pb push_back
#define ll long long
using namespace std;
const int inf=1e9;
const int mod=1e9+7;
const int maxn=2e6+10;
char s[maxn];
int n,nex[maxn];
int Get_min()
{
    int i = 0,j = 1,k = 0,t;
    while(i < n && j < n && k < n)
    {
        t = s[(i+k)%n] - s[(j+k)%n];
        if(!t) k++;
        else
        {
            if(t > 0) i += k+1;
            else j += k+1;
            if(i == j) j++;
            k = 0;
        }
    }
    return i >j ?j :i;
}
int Get_max()
{
    int i = 0,j = 1,k = 0,t;
    while(i < n && j < n && k < n)
    {
        t = s[(i+k)%n] - s[(j+k)%n];
        if(!t) k++;
        else
        {
            if(t > 0) j += k+1;
            else i += k+1;
            if(i == j) i++;
            k = 0;
        }
    }
    return i >j ?j :i;
}
int exkmp(int pos){
    int i=pos+1,j=0,p0=pos+1,cnt=1;
    while(i<2*n&&j<n&&s[i]==s[j+pos]) ++i,++j;
    nex[p0]=j;if(j==n) ++cnt;
    for(int i=pos+2;i<n;i++){
        j=max(0,min(nex[p0]+p0-i,nex[i-p0+pos]));
        if(i+j<nex[p0]+p0){
            nex[i]=j;
        }else{
            int k=i+j;
            while(k<2*n&&j<n&&s[k]==s[j+pos]) ++k,++j;
            nex[i]=j;p0=i;
        }
        if(nex[i]==n) ++cnt;
    }
    return cnt;
}
int main(){
    //ios::sync_with_stdio(false);
    //freopen("in","r",stdin);
    while(~scanf("%s",s)){
        n=strlen(s);
        for(int i=n;i<2*n;i++) s[i]=s[i-n];
        int j=Get_min();
        printf("%d %d ",j+1,exkmp(j));
        j=Get_max();
        printf("%d %d\n",j+1,exkmp(j));
    }
    return 0;
}

原文地址:https://www.cnblogs.com/xyq0220/p/11495146.html

时间: 2024-08-28 23:03:17

HDU 3374 exkmp+字符串最大最小表示法的相关文章

循环字符串最大最小表示法模版

循环字符串最大最小表示法模版 定义字符串abcde和cdeab同构,因为abcde转两格即为cdeab,该字符串称为循环字符串. 循环字符串的字典序最小的同构字符串称为最小表示,最大表示同理. 这里只给模版,以后再深究. int getMin(char *s) ///返回首位置 { int n=strlen(s); 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(

【算法】字符串的最小表示法

字符串的最小表示法,就是对于一个字符串,可以将它的最后一位放到第一位来,依次类推,一共有n种变形,n为字符串长度 例如: s="00ab" 变形有(省略引号)b00a ab00 0ab0 一共4种 那么找到其中字典序最小的一个,用的算法便是这个. 定义三个指针,i,j,k 初始i=0;j=1;k=0 首先,如果s[i]<s[j]那么很明显j++ 如果s[i]>s[j]那么也很明显i=j++ 省下的就是如果s[i]==s[j]的时候. 这时候有一个性质就是在i和j之间的所有的

字符串的最小表示法

给定一个字符串,要求求出从某个下标开始,这个字符串的字典序最小,即字符串的最小表示法比如字符串bbbaaa,从下标3开始表示为aaabbb,字典序最小 暴力算法的时间复杂度为O(n^3)但是有线性的算法初始时,让i=0,j=1,k=0:分为三种情况,①如果str[i+k] == str[j+k] k++;②如果str[i+k] > str[j+k] i = i + k + 1, k = 0,  即最小表示不可能以str[i-->i+k]中的任一一个字符串开头③如果str[i+k] < s

HDU 4162 Shape Number(字符串,最小表示法)

HDU 4162 题意: 给一个数字串(length <= 300,000),数字由0~7构成,求出一阶差分码,然后输出与该差分码循环同构的最小字典序差分码. 思路: 第一步是将差分码求出:s[i] = (s[i] - s[i+1] + 8) % 8; 第二步是求出最小字典序的循环同构差分码,我之前没注意到字符串规模..直接用set做,MLE+TLE... 正确的方式应该是一种O(n)的解法,即最小表示法.//关于最小表示法的证明与详述请参考最小表示法:) 最小表示法算法: 初始时,i=0,j=

字符串最大最小表示法模板 ( 字典序最大最小 )

模板 int getMin(char *s) { int i = 0, j = 1, l; int len = strlen(s); while(i < len && j < len) { for(l = 0; l < len; l++) if(s[(i + l) % len] != s[(j + l) % len]) break; if(l >= len) break; if(s[(i + l) % len] > s[(j + l) % len]) { if

USACO 5.5.2 字符串的最小表示法

这道题是最小表示法的一个应用, 代码如下: /* ID: m1500293 LANG: C++ PROG: hidden */ #include <cstdio> #include <algorithm> #include <cstring> using namespace std; char s[100000 + 100]; int len; int mins(char s[], int len) { int i=0, j=1, k=0; while(i<len

HDU 4162 Shape Number (最小表示法)

题意:给你一串n个数,求出循环来看一阶差的最小字典序:数字串看成一个顺时针的环,从某一点开始顺时针循环整个环,保证字典序最小就是答案 例如给你 2 1 3 就会得到(1-2+8 注意题意负数需要加8) (3-1) (2-3+8)-> 7 2 7 答案就是2 7 7. 典型的最小表示法.线性时间内求出最小字典序. 首先复制一遍数字串在原串后面,这样从原串任意位置开始向再后n个位置就是答案.接着双指针维护,直接双指针暴力比较数字串,当出现不同数字时,就把字典序大的那个指针向后移动尽量多的位置这样可以

hdu 2609 How many(最小表示法)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2609 题意:给你n个字符串每个字符串可以左右移动但还是同一串比如 0110 可以表示为 0110 -> 1100 -> 1001 -> 0011->0110 这些都属于同一个字符串,最后问这n个字符串里一共有多少不同的字符串 可以将这些字符串都以其最小表示方法存下来复杂度为O(n)然后在sort一遍找一下有几个不同的就行了. #include <iostream> #inc

String Problem - HDU 3374 (kmp+最大最小表示)

题目大意:有一个字符串长度为N的字符串,这个字符串可以扩展出N个字符串,并且按照顺序编号,比如串  ” SKYLONG “ SKYLONG 1 KYLONGS 2 YLONGSK 3 LONGSKY 4 ONGSKYL 5 NGSKYLO 6 GSKYLON 7 下面这7个都是原串的扩展(循环位移),现在需要求出来字典序最小的和字典序最大的那个串的标号.   输出说明:最小字典序的编号,最小字典序个数,最大字典序编号,最大字典序个数.   分析:以前也遇到过类似的求最小字典序的问题,不过当时不会