Favorite Donut--hdu5442(2015年长春网选赛,kmp,最大表示法)

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

打比赛的时候还没学kmp更没有学最大最小表示法,之后做完了kmp的专题,学了它们,现在再来做这道题,断断续续做了一段时间最终还是对了;

题意:就是有一个甜圈由n个部分组成,每部分的甜度由一个小写字母来表示(z是最甜的,a是最不甜的),Lulu吃它的时候必须从一个部分开始,然后必须吃这部分相邻的部分,一直到把n部分吃完为止;所以她只有两种吃法:正序或逆序;但是她总是喜欢吃最甜的你,总是选择字典序最大的来吃当有多种字典序相等的时候选择开始下标最小的,当下标也相等的时候则选择正序;

思路:求最大字典序我们可以用最大表示法来求,我们用s0来存两次串的正序,s1来存两次串的逆序,然后分别求出s0,s1中的最大字典序序列并分别存入a b中,但是b是逆序的,所以我们必须要求出来b串在s1中最先先出现的位置(最后面的位置);所以可以用kmp进行匹配;

看代码吧

#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
#define N 40200

char s[N], s0[N], s1[N], a[N], b[N];
int Next[N];

int MAX_INDEX(char s[], int n)///最大表示法求最大字典序的起始下标;
{
    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);
}

void GetNext(char s[], int n)///求子串的Next数组;
{
    int i=0, j=-1;
    Next[0] = -1;
    while(i<n)
    {
        if(j==-1 || s[i]==s[j])
            Next[++i] = ++j;
        else
            j = Next[j];
    }
}

int kmp(char sub[], int n, char Mum[], int m)///长度为n的子串在长度为m的母串中的位置,并返回开始匹配的下标,若没有返回-1;
{
    int i=0, j=0;
    while(i<m)
    {
        if(j==-1 || Mum[i]==sub[j])
            i++,j++;
        else
            j = Next[j];
        if(j==n)
            return i-n+1;
    }
    return -1;
}

int main()
{
    int T, dir,ans;
    scanf("%d", &T);
    while(T--)
    {
        memset(a, 0, sizeof(a));
        memset(b, 0, sizeof(b));
        memset(s0, 0, sizeof(s0));
        memset(s1, 0, sizeof(s1));

        int len;
        scanf("%d%s", &len, s);

        strcpy(s0, s);
        strcat(s0, s);///正着存两次放进s0;
        s0[2*len] = ‘\0‘;

        int j=0;
        for(int i=2*len-1; i>=0; i--)
            s1[j++] = s0[i];
        s1[j] = ‘\0‘;///倒着存两次放进s1;

        int Max_index1 = MAX_INDEX(s0, 2*len);
        int Max_index2 = MAX_INDEX(s1, 2*len);///用最大表示法求出最大字典序的下标;

        strncpy(a, s0+Max_index1, len);
        strncpy(b, s1+Max_index2, len);
        a[len] = ‘\0‘; b[len] = ‘\0‘;///分别用字符串a,b来保存正序和逆序的最大字典序的字符;

        GetNext(b, len);

        int m = kmp(b, len, s1+Max_index2+1, 2*len-Max_index2-1);
        while(m!=-1 && m+Max_index2!=len)///下标不能是len;
        {
            Max_index2 += m;
            m = kmp(b, len, s1+Max_index2+1, 2*len-Max_index2-1);
        }///因为s1串是逆序的用最大表示法得到的下标在逆序中是最靠前的,然而在正序中确实最靠后的,所以要用kmp求出s1串中与b一样的串最后的位置所在;

        if(strcmp(a, b)>0)
            dir = 0, ans = Max_index1 + 1;
        else if(strcmp(a, b)<0)
            dir = 1, ans = len - Max_index2;
        else///当串一样时, 要考虑谁考前,结果就是谁;
        {
            if(Max_index1 + 1 <= len - Max_index2)
                dir = 0, ans = Max_index1 + 1;
            else
                dir = 1, ans = len - Max_index2;
        }
        printf("%d %d\n", ans, dir);
    }
    return 0;
}

时间: 2024-11-08 01:43:58

Favorite Donut--hdu5442(2015年长春网选赛,kmp,最大表示法)的相关文章

字符串处理 2015百度之星资格赛 1002 列变位法解密

题目传送门 1 /* 2 字符串处理:要求解码,然而二维数组开不下,可以直接输出 3 只要在余数的地方判断一下就行了,vector的效率不高 4 另外:感觉麻烦的地方应该纸上写写就清楚了 5 */ 6 #include <cstdio> 7 #include <iostream> 8 #include <algorithm> 9 #include <cstring> 10 #include <string> 11 #include <cma

ACM学习历程—HDU 5443 The Water Problem(RMQ)(2015长春网赛1007题)

Problem Description In Land waterless, water is a very limited resource. People always fight for the biggest source of water. Given a sequence of water sources with a1,a2,a3,...,an representing the size of the water source. Given a set of queries eac

ACM学习历程—HDU 5446 Unknown Treasure(数论)(2015长春网赛1010题)

Problem Description On the way to the next secret treasure hiding place, the mathematician discovered a cave unknown to the map. The mathematician entered the cave because it is there. Somewhere deep in the cave, she found a treasure chest with a com

hdu 5443 (2015长春网赛G题 求区间最值)

求区间最值,数据范围也很小,因为只会线段树,所以套了线段树模板=.= Sample Input3110011 151 2 3 4 551 21 32 43 43 531 999999 141 11 22 33 3 Sample Output1002344519999999999991 1 # include <iostream> 2 # include <cstdio> 3 # include <cstring> 4 # include <algorithm>

ACM学习历程—HDU 5451 Best Solver(Fibonacci数列 &amp;&amp; 快速幂)(2015长春网赛1007题)

Problem Description The so-called best problem solver can easily solve this problem, with his/her childhood sweetheart. It is known that y=(5+2√6)^(1+2^x).For a given integer x (0≤x<2^32) and a given prime number M (M≤46337) , print [y]%M . ([y] mean

hdu5442(2015长春赛区网络赛1006)后缀数组+KMP /最小表示法?

题意:给定一个由小写字母组成的长度为 n 的字符串,首尾相连,可以从任意一个字符开始,顺时针或逆时针取这个串(长度为 n),求一个字典序最大的字符串的开始字符位置和顺时针或逆时针.如果有多个字典序最大的字符串,优先选择开始位置靠前的,如果开始位置相同,优先选择顺时针. 这种字符串的问题,第一反应是后缀数组,为了达到首尾相连的目的,所以先复制了一个两倍长的该字符串,然后再将串倒置,也弄成两倍长度,得到顺逆时针的两倍长的串,并对这两个字符串分别做后缀数组,得到 sa 数组(该串字典序第几小的后缀的开

hdu 5441 Travel (2015长春网赛)

http://acm.hdu.edu.cn/showproblem.php?pid=5441 题目大意是给一个n个城市(点)m条路线(边)的双向的路线图,每条路线有时间值(带权图),然后q个询问,每个询问一个时间值 求不大于这个时间的可以连通的城市有多少种连法 比如样例中第一个询问6000,不大于6000时间值的连通城市有3,5.所以有3-->5,5-->3两种 第二个询问10000,符合条件的连通的城市有2,3,5,所以有2-->3,3-->2,2-->5,5-->2

2015 CVTE校招网测部分试题(技术类)

CVTE的网测题分为技术题与行测题,都非常基础非常简单,但也有较难的题目,下面这些题都是我当时觉得稍有些难或容易答错或值得进一步推敲的题,现在分享出来,大家可以对着知识点做下,不会的Google,务必将每一个知识点都弄懂. 注意:下面的试题已选项不代表真实答案,但鼓励大家将自己的答案贴在下面,好互相对照.

hdu5438 dfs+并查集 长春网赛

先dfs对度小于2的删边,知道不能删为止. 然后通过并查集来计算每一个分量里面几个元素. #include<iostream> #include<cstring> #include<vector> #define maxn 10010 #define LL __int64 using namespace std; int in[maxn],vis[maxn],p,pa[maxn],cou[maxn]; LL sum[maxn]; vector<int>mp[