#HDU 3746 Cyclic Nacklace (KMP + 循环填补 原理)

Problem Description

CC always becomes very depressed at the end of this month, he has checked his credit card yesterday, without any surprise, there are only 99.9 yuan left. he is too distressed and thinking about how to tide over the last days. Being inspired by the entrepreneurial spirit of "HDU CakeMan", he wants to sell some little things to make money. Of course, this is not an easy task.

As Christmas is around the corner, Boys are busy in choosing christmas presents to send to their girlfriends. It is believed that chain bracelet is a good choice. However, Things are not always so simple, as is known to everyone, girl's fond of the colorful decoration to make bracelet appears vivid and lively, meanwhile they want to display their mature side as college students. after CC understands the girls demands, he intends to sell the chain bracelet called CharmBracelet. The CharmBracelet is made up with colorful pearls to show girls' lively, and the most important thing is that it must be connected by a cyclic chain which means the color of pearls are cyclic connected from the left to right. And the cyclic count must be more than one. If you connect the leftmost pearl and the rightmost pearl of such chain, you can make a CharmBracelet. Just like the pictrue below, this CharmBracelet's cycle is 9 and its cyclic count is 2:


Now CC has brought in some ordinary bracelet chains, he wants to buy minimum number of pearls to make CharmBracelets so that he can save more money. but when remaking the bracelet, he can only add color pearls to the left end and right end of the chain, that is to say, adding to the middle is forbidden.
CC is satisfied with his ideas and ask you for help.

Input

The first line of the input is a single integer T ( 0 < T <= 100 ) which means the number of test cases.
Each test case contains only one line describe the original ordinary chain to be remade. Each character in the string stands for one pearl and there are 26 kinds of pearls being described by 'a' ~'z' characters. The length of the string Len: ( 3 <= Len <= 100000 ).

Output

For each case, you are required to output the minimum count of pearls added to make a CharmBracelet.

Sample Input

 

3 aaa abca abcde

Sample Output

 

0 2 5

题目大意 : 输入一个字符串, 求出最少在左边或右边添加多少个字符,才能使他变成N个循环体构成的字符串

写完这道题以后看了下别人的解析, 发现对于这道题比较关键的一步基本上都一带而过了, 有的人可能看的似懂非懂, 所以我稍微写详细点~ 

思路 : 首先看样例给的数据, 正好概括了这道题所有的情况 : 一、 输入的字符串已经是周期字符串了,如  “aaa” ,那么答案就是0  二、输入的字符串循环体长度是整个字符串, 如  “abcde”, 答案就是整个字符串的长度  三、输入的字符串循环体长度   >   1, 但是后缀  > 1 并且  <  循环体长度,我们主要来讨论这种情况。

当不是一、 二两种情况时, 该字符串已经存在循环结构但是最后一个循环体没有循环结束,所以我们只需要考虑最后一个循环体就好, 先看看题目给的样例 : abca  。学完KMP应该知道, 当操作到i时, i - nxt[i]就是目前为止从1到i的循环体“应该有”的长度, 为什么呢?首先在nxt数组里, 他表示的就是前缀与后缀相等时的最大长度, 换句话说, 就是你从1往后看 和 你从i 往前看, 如果str【1】 ==str【i】, 1 - > 2, i - > i  - 1, 直到他们不相等,此时操作的次数就是nxt[i], 具体怎么实现大家可以看看这个大佬的博客,讲的非常详细https://blog.csdn.net/v_july_v/article/details/7041827

之所以是“应该有”这么个说法, 是因为第三种情况的最后一次循环并没有结束, 否则他就是第一种情况直接输出0了, 所以我们需要做的就是 让最后一个循环的长度增加到他应有的长度, 也就是 i - nxt[i], 在这道题里, 就是字符串长度 len - nxt[len], 那么需要加多少呢?这又有两种情况,把这两情况弄明白, 你就懂啦!(先讲好理解的写法, 简洁的写法在你看懂后自然就会了 QAQ)

比如字符串 “abababa”, 长度len = 7, nxt【7】 = 5, 循环体长度 = len - nxt【7】 =2, 很显然需要添加一个字符就OK;

再看一个 “abcdeab”, 长度为7, nxt【7】 = 2, 循环体长度  5, 需要添加3个

举这两个栗子, 是因为第一个循环体已经循环了很多次, 而第二个循环体只循环了一次, 这样, 所有的情况也都考虑到了。为了防止循环体长度较小的那种情况出现 我们把它加到大于他的长度, 然后用加完之后的长度 % 现在字符串的总长,对于第一个, 就是(2 + 2 + 2 + 2) % 7 == 1, 对于第二种 就是 (5 + 5) % 7 == 3, 这下明白了吧, 超过他再看比他多多少。

更简单的写法 : 一、2 - (7 % 2), 二、5 - (7 % 5).

AC代码 :

#include<iostream>
#include<cstring>
using namespace std;
const int maxn = 1e5 + 5;

char str[maxn];
int nxt[maxn], len_, T;
void getnext() {
    nxt[0] = -1;
    int i = 0, j = -1;
    while (i < len_) {
        if (j == -1 || str[i] == str[j])
            nxt[++i] = ++j;
        else
            j = nxt[j];
    }
}

int main()
{
    scanf("%d", &T);
    while (T--) {
        memset(nxt, 0, sizeof(nxt));
        scanf("%s", str);
        len_ = strlen(str);
        getnext();
        if (nxt[len_] == 0) cout << len_ << endl;
        else if (len_ % (len_ - nxt[len_]) == 0) cout << 0 << endl;
        else cout << (len_ - nxt[len_]) - (len_ % (len_ - nxt[len_])) << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_43851525/article/details/91650232
今日推荐