最大最小表示法kmp 综合应用

题目链接

这道题就是在理解上很迷胡 什么字典上第一个串的排位 其实就是找通过左移每次移动一个字符生成的所有串重复的个数 求第一个字典序最小的串出现的时候移动了多少次 移动的次数加一就是第一个答案 也就是 如果有多个相同的字典序串 找第一次最小字典序出现的排名,第二个答案就是相同的最小字典序串的重复次数 第三个答案找最大字典序串 第四个答案就是相同最大字典序串的重复次数
举个例子 a b c d这样的字符串 a b c d就是最小字典序串 d a b c就是最大字典序串。 这里有一个算是定理的玩意儿 就是 最大字典序串和最小字典序串出现次数是相同的 就是存在循环节 最小的循环节 的个数就是字典序串出现的次数
这里的循环节就是最小的重复单元 从开始重复到最后都能匹配 如 a b a b a b 最小循环节 a b 如 a b a 中 a b就不是循环节 因为最后a b匹配后留下的a 无法和a b匹配 然后就找循环节吧和字典序最小的串和字典序最大的串循环节很好找了主要是字典序不太好找 就是最小最大表示法
来一个思考过程 首先定一个指标 i =0 j=1 k=0 i表示 当前最小 j表示后面是否有比i还要小的字典序 k就是比较过程 出现不一致的移动i或j 使其继续比较直到超出字符串长 即所有字典序字符串全部都比较过了, 存在比i还小的字典序字符串就把i指向那个字典序开头的字母,这里解释一下最小字典序 最大同理 只不过 j表示找比i还大的字典序字符串的字母开头。。。。如果这些理解不了 菜鸡哭哭。
代码来了

#include <map>
#include <set>
#include <list>
#include <queue>
#include <deque>
#include <cmath>
#include <stack>
#include <vector>
#include <cstdio>
#include <string>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
char a[2000005];
int  f[2000005],exf[205];
void fc(char *p,int l)
{
    int i=0;
    int j=-1;
    f[0]=-1;
    while(i<l)
    {
        while(j==-1||p[i]==p[j])
        {
            f[++i]=++j;
        }
        if(p[i]!=p[j])
        {
            j=f[j];
        }
    }


}
int getminmax(int flag,char *p)
{
   // char x[2000005];
    int  lp=strlen(p);
    int i=0,j=1,k=0;
    while(i<lp&&j<lp&&k<lp)
    {

        int t=p[(i+k)%lp]-p[(j+k)%lp];
        if(t==0)
        {
            k++;

        }
        else
        {
            if(t>0)
            {
                if(flag)
                {
                    j+=k+1;
                }
                else
                {
                    i+=k+1;
                }
            }
            else
            {
                if(flag)
                {
                    i+=k+1;

                }
                else
                {
                    j+=k+1;
                }

            }
            if(j==i)
            {
                j++;
            }
            k=0;
        }
    }
    return min(i,j);
}
bool kmp(char *p,int l1,char *q,int l2 )
{

    int j=0;
    int i=0;
    while(i<l2)
    {
      if(j==-1||q[i]==p[j])
        {
           ++i;
           ++j;
        }
        else
        {
            j=f[j];
        }
        if(j==l1)
        {
            return true;
        }
    }
    return false;
//
//   int j=-1;//会wa原因是我不知道求大佬评论区解答一下哇
// for(int w=0;w<l2;w++)
// {
//     if(q[w]==p[j+1])
//     {
//         j++;
//     }
//     while(j>-1&&q[w]!=p[j+1])
//     {
//         j=f[j];
//     }
//     if(j+1==l1)
//     {
//        return true;
//     }
// }
//   return false;

}
int main()
{
    while(scanf(" %s",a)!=EOF)
    {
        int l;
        l=strlen(a);
        char *pp;
        pp=a;
      fc(pp,l);
      int minn;
      int maxx;
      int time;
      time=1;
      int lenloop=l-f[l];
      if(l%lenloop==0)
      {
          time=l/lenloop;
      }
      minn=getminmax(0,pp);
      maxx=getminmax(1,pp);
        printf("%d %d %d %d\n", minn+1 ,time,maxx+1 ,time);
      memset(a,'\0',sizeof(a));
      memset(f,0,sizeof(f));
    }
    return 0;
}
//    int n;//理解错误就会wa
//    while(~scanf("%s",&a))
//    {
//       int l=strlen(a);
//       //memset(a,'\0',sizeof(a));
//       char t[32];
//       int w[32];
//       int tail=0;
//       int head=9999;
//       int cx[32];
//       int zh[32];
//
//       for(int i=1;i<=26;i++)
//       {
//           t[i]=i+'a'-1;
//           w[i]=0;
//           cx[i]=9999999;
//           zh[i]=9999999;
//           for(int j=0;j<l;j++)
//           {
//               if(t[i]==a[j])
//               {
//                   if(head>i)
//                   {
//                    head=i;
//                   }
//                   if(tail<i)
//                   {
//                     tail=i;
//                   }
//                   w[i]++;
//               }
//           }
//       }
//       for(int i=1;i<=26;i++)
//       {
//           for(int j=0;j<l;j++)
//           {
//               if(t[i]==a[j])
//               {
//                if(head==i)
//                if(cx[head]>j+1)
//                    cx[head]=j+1;
//                if(tail==i)
//                if(zh[tail]>j+1)
//                    zh[tail]=j+1;
//               }
//           }
//       }
//       printf("%d %d %d %d\n",cx[head],w[head],zh[tail],w[tail]);
//       memset(a,'\0',sizeof(a));
//       memset(f,0,sizeof(f));
//    }


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值