hdu 5442 Favorite Donut 最大表示法+KMP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5442

题意:

有一个由小写字母组成的字符串(长度为n),首尾相接,求顺时针转和逆时针转的情况下,长度为n的最大字典序的字符串的首位的位置。

如果顺时针和逆时针求得的字符串相同,则选择开始位置较前的,如果开始位置也相同,则选择顺时针的。

如abcd,那么顺时针可以是abcd,bcda,cdab,dabc.逆时针可以是adcb,dcba,cbad,badc.

思路:

顺时针的情况下,直接求最大字典序的位置。逆时针的情况下,由于求最大字典序的串与原串对应位置的编号发生变化,

所以求得位置后,得到字典序最大的字符串,再用kmp找出该字符串在母串中出现的所有位置,取最靠前的位置。

然后把顺时针和逆时针的情况进行比较。

  1 #include<iostream>
  2 #include<string>
  3 #include<cstring>
  4 #include<cstdio>
  5 using namespace std;
  6 int n;
  7 char S[20010*2];
  8 int Next[1000005];
  9 char P[20010*2];
 10 int idb[20010*2];
 11 int bpos1;
 12 void getNext(char* S,int* Next){
 13     int n=strlen(S);
 14     Next[0]=Next[1]=0;
 15     for(int i=1; i<n; ++i){
 16         int j=Next[i];
 17         if(j && S[i]!=S[j]) j=Next[j];
 18         Next[i+1] = S[i]==S[j]?1+j:0;
 19     }
 20 }
 21
 22 void find(char* S,char* P,int* Next){
 23     getNext(P,Next);
 24     int n=strlen(S);
 25     int m=strlen(P);
 26     int j=0;
 27     int cnt=0;
 28     for(int i=0; i<n; ++i){
 29         while(j && S[i]!=P[j]) j=Next[j];
 30         if(S[i] == P[j]) ++j;
 31         if(j==m){
 32             if(idb[i-m+1] <= bpos1)
 33             {
 34                 bpos1 = idb[i-m+1];
 35
 36             }
 37         }
 38     }
 39 }
 40
 41 int GetMax(char *P)
 42 {
 43     int len=n;
 44     int i=0,j=1,k=0;
 45     while(i<len&&j<len&&k<len)
 46     {
 47         int t=P[(i+k)%len]-P[(j+k)%len];
 48         if(!t) k++;
 49         else
 50         {
 51             if(t>0) j+=k+1;
 52             else i+=k+1;
 53             if(i==j) j++;
 54             k=0;
 55         }
 56     }
 57     return i<j?i:j;
 58 }
 59 char s1[20010];
 60 char s2[20010];
 61 int main()
 62 {
 63     int T;
 64     scanf("%d", &T);
 65     while(T--)
 66     {
 67         scanf("%d", &n);
 68         scanf("%s", s1);
 69         s2[0] = s1[0];
 70         for(int i = 1; i < n; i++) s2[i] = s1[n-i];
 71
 72         idb[0] = 0;
 73         for(int i = 1; i < n; i++) idb[i] = n-i;
 74         for(int i = n; i < 2*n; i++) idb[i] = idb[i-n];
 75
 76         int apos = GetMax(s1);
 77         int bpos = GetMax(s2);
 78         int apos1 = apos;
 79
 80         bpos1 = idb[bpos];
 81
 82
 83         string a = "", b = "";
 84         for(int i = apos; i < apos+n; i++) a += s1[i%n];
 85         for(int i = bpos; i < bpos+n; i++) b += s2[i%n];
 86
 87         for(int i = 0; i < n; i++) S[i] = s2[i];
 88         for(int i = n; i < 2*n; i++) S[i] = s2[i-n];
 89         S[2*n] = ‘\0‘;
 90
 91         char b1[20010];
 92         for(int i = 0; i < n; i++) b1[i] = b[i];
 93         b1[n] = ‘\0‘;
 94
 95         find(S, b1, Next);
 96
 97         if(a>b) printf("%d %d\n", apos+1, 0);
 98         else if(a < b) printf("%d %d\n", bpos1+1, 1);
 99         else
100         {
101             if(apos1 <= bpos1) printf("%d %d\n", apos1+1, 0);
102             else printf("%d %d\n", bpos1+1, 1);
103         }
104
105     }
106     return 0;
107 }
时间: 2024-08-27 14:45:34

hdu 5442 Favorite Donut 最大表示法+KMP的相关文章

Hdu 5442 Favorite Donut (2015 ACM/ICPC Asia Regional Changchun Online 最大最小表示法 + KMP)

题目链接: Hdu 5442 Favorite Donut 题目描述: 给出一个文本串,找出顺时针或者逆时针循环旋转后,字典序最大的那个字符串,字典序最大的字符串如果有多个,就输出下标最小的那个,如果顺时针和逆时针的起始下标相同,则输出顺时针. 解题思路: 看到题目感觉后缀数组可以搞,正准备犯傻被队友拦下了,听队友解释一番,果断丢锅给队友.赛后试了一下后缀数组果然麻烦的不要不要的(QWQ),还是最大最小表示法 + KMP来的干净利索. 最大表示法:对于一个长度为len文本串,经过循环旋转得到长度

HDU 5442——Favorite Donut——————【最大表示法+kmp | 后缀数组】

Favorite Donut Time Limit: 1500/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1702    Accepted Submission(s): 430 Problem Description Lulu has a sweet tooth. Her favorite food is ring donut. Everyday she buy

hdu 5442 Favorite Donut 后缀数组

Favorite Donut Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://acm.hdu.edu.cn/showproblem.php?pid=5442 Description Lulu has a sweet tooth. Her favorite food is ring donut. Everyday she buys a ring donut from the same bakery. A ring donut is consis

【HDU - 5442】Favorite Donut 【最大表示法+KMP/后缀数组】

题意 给出一个长度为n的环状由小写字母组成的序列,请找出从何处断开,顺时针还是逆时针,使得字典序最大.如果两个字符串的字典序一样大,那么它会选择下下标最小的那个.如果某个点顺时针逆时针产生的字典序大小相同,那么优先选择顺时针的. 这个题用最大表示法+KMP很容易解决.因为最大表示法找到的是下表最小的那个字典序最大的字符串,所以正向的时候最大表示法找出来的就直接是答案,关键是逆时针的时候.我们将字符串翻转以后用最大表示法找到那个字符串s2,然后用KMP算法在翻转*2后的串中找出最后面的那个s2,这

HDU 2594 Simpsons’ Hidden Talents (字符串-KMP)

Simpsons' Hidden Talents Problem Description Homer: Marge, I just figured out a way to discover some of the talents we weren't aware we had. Marge: Yeah, what is it? Homer: Take me for example. I want to find out if I have a talent in politics, OK? M

hdu 2609 How many 最小表示法

How many Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 1248    Accepted Submission(s): 486 Problem Description Give you n ( n < 10000) necklaces ,the length of necklace will not large than 100

hdu how many prime numbers 筛选法求素数

/* * hdu How many prime numbers * date 2014/5/13 * state AC */ #include <iostream> #include <cmath> #include <cstdio> using namespace std; bool isPrime(int x) { int sqr=sqrt(x*1.0); for(int i=2;i<=sqr;i++) { if(x%i==0)return false; }

HDU 3374 最小/大表示法+KMP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3374 题意:给定一个串s,该串有strlen(s)个循环同构串,要求输出字典序最小的同构串的下标,字典序最小的出现次数,最大的同构串的下标,字典中最大的出现次数. 思路:对于求循环同构的字典序最小可以用最小表示法求得,最大也是一样.然后设ds为字符串s+s.然后就可以用KMP求最小串在ds出现的次数和最大串出现的次数了. #define _CRT_SECURE_NO_DEPRECATE #inclu

HDU 5442 后缀自动机+kmp

题目大意: 给定一个字符串,可理解成环,然后选定一位置,逆时针或顺时针走一遍,希望得到字典序最大,如果同样大,希望找到起始位置最小的,如果还相同,就默认顺时针 比赛一直因为处理最小位置出错,一结束就想明白了...真是作孽 这里正向后缀自动机跑一遍最大的,这样得到的位置肯定是最小的 而逆时针最大就反向重建后缀自动机再跑一遍最大的,但这样因为后缀自动机跑出的位置是最小的,但返回来就变成最大的位置了 如果存在更小的位置,那么就相当于可以从开头拎出一段移到末尾,那么必然是产生一个循环节,这个长度可以利用