【扩展KMP + KMP之next[]数组应用_循环节】HDU 4333 Revolving Digits(呼~的一下发现,其实KMP可以废掉,根本就用不到啊TAT)

HDU 4333 Revolving Digits

  • 题意:给一个长度为10^100000的数,让我们求它循环移位可以得到的不同数字中(去重去重去重!!!),小于它的个数、等于它的个数、大于它的个数。

思路:

数据范围过大,肯定是读字符串啦~但是怎么处理呢?既然是循环移位得到的数字,那么我们将字符串完整复制放在末尾,就可以得到所有移位可以得到的数字。举个栗子:t = 123,s = 123123

扩展KMP

那么我们以 s 为文本串,以 t 为模式串跑扩展KMP,得到 s 的extend[ ]. 那么就有以下三种情况

  1. 当extend[ i ] == t_len时,说明s[i, i + 1, ..., i + t_len)和模式串 t 相等
  2. 当s[ i + extend[ i ] ] > t[ extend[ i ] ]时,说明s[i, i + 1, ..., i + t_len)大于模式串 t. 【extend[ i ]是s[i, ... s_len)与 t 的最大相同前缀的长度,所以两者第一个不同的字符就是s[ i + extend[ i ] ]和t[ extend[ i ] ] 】
  3. 当s[ i + extend[ i ] ] < t[ extend[ i ] ]时,说明s[i, i + 1, ..., i + t_len)小于模式串 t.  【原理与上面第二条类似】

去重(KMP)

接下来就到了去重的时候了!我们需要判断原串是不是有循环节!比如这种101010,那么10就是它的循环节. 因为题目要求不能有重复数字的嘛,所以相等的肯定就是1个不可置疑!那么如果相等的个数有kind个,那么就说明三个答案都重复了kind次。【所以说到这里,重复次数就是_equal(和原串相等的个数)??于是发现根本用不到KMP,直接扩展KMP,然后遍历一遍就完事,每个答案都除以_equal即可,代码贴了一份放最后了~】

但还是说完KMP叭TAT!举个栗子:t = 1010,s = 10101010

因为t = 1010 有两个循环节10. 所以会重复两次。

  • 我们知道循环节的长度可以由cycL = len - Next[ len ]得到。如果不知道为什么的建议做做这道题
  • 重复次数=循环节的个数= len / cycL。
  • 如何判断字符串是不是循环节个数>1的循环字符串?Next[len] != 0 && len % cycL == 0 

END


OS: 又双叒叕是怀疑大佬博客的一天!TAT,因为读错题,导致我带着我以为的题意去看他们的博客,于是我GG了!TAT. 怎么就是没看到different!!!!!!!!!!!!!TAT...

不过又复习了下KMP的next[]循环节问题,还是颇有收获滴~


AC CODE【扩展KMP+(其实可以废掉的)KMP做法】

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 2000000 + 7;
int Next[maxN], extend[maxN];
void GetNext(string t, int len)
{
    int front = 0, p = 0;
    Next[0] = len;
    for(int i = 1; i < len; i ++ )
    {
        if(i >= p || i + Next[i - front] >= p)
        {
            if(i >= p) p = i;
            while(p < len && t[p] == t[p - i]) ++ p;
            Next[i] = p - i;
            front = i;
        }else Next[i] = Next[i - front];
    }
}
void GetExtend(string s, int s_len, string t, int t_len)
{
    GetNext(t, t_len);
    int front = 0, p = 0;
    for(int i = 0; i < s_len; i ++ )
    {
        if(i >= p || i + Next[i - front] >= p)
        {
            if(i >= p) p = i;
            while(p < s_len && p - i < t_len && s[p] == t[p - i]) ++ p;
            extend[i] = p - i;
            front = i;
        }else extend[i] = Next[i - front];
    }
}
void kmp(string t, int len)
{
    int i = 0, j = -1;
    Next[0] = -1;
    while(i < len)
    {
        if( j == -1 || t[i] == t[j])
        {
            ++ i; ++j;
            if(t[i] != t[j]) Next[i] = j;
            else Next[i] = Next[j];
        } else j = Next[j];
    }
}
string s, t;
int main()
{
    int cas = 0;
    int TAT; scanf("%d", &TAT);
    while(TAT -- )
    {
        cin >> t;
        s = t + t;
        int t_len = t.size(), s_len = s.size();
        GetExtend(s, s_len, t, t_len);
        kmp(t, t_len);
        int cycL = t_len - Next[t_len], kind = 1;
        if(Next[t_len] && t_len % cycL == 0)
            kind = t_len / cycL;
        int _min = 0, _equal = 0, _max = 0;
        for(int i = 0; i < t_len; i ++ )
        {
            if(extend[i] == t_len)
                ++ _equal;
            else
            {
                if(s[i + extend[i]] > t[extend[i]])
                    ++ _max;
                else
                    ++ _min;
            }
        }
        printf("Case %d: %d %d %d\n", ++ cas, _min / kind, _equal / kind, _max / kind);
    }
    return 0;
}

 ONLY 扩展KMP的简单做法

  • 上面的KMP讲真,真的做麻烦了~但是还好,总归复习了一下next[]的应用哈哈~ 
#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#define INF 0x3f3f3f3f
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxN = 2000000 + 7;
int Next[maxN], extend[maxN];
void GetNext(string t, int len)
{
    int front = 0, p = 0;
    Next[0] = len;
    for(int i = 1; i < len; i ++ )
    {
        if(i >= p || i + Next[i - front] >= p)
        {
            if(i >= p) p = i;
            while(p < len && t[p] == t[p - i]) ++ p;
            Next[i] = p - i;
            front = i;
        }else Next[i] = Next[i - front];
    }
}
void GetExtend(string s, int s_len, string t, int t_len)
{
    GetNext(t, t_len);
    int front = 0, p = 0;
    for(int i = 0; i < s_len; i ++ )
    {
        if(i >= p || i + Next[i - front] >= p)
        {
            if(i >= p) p = i;
            while(p < s_len && p - i < t_len && s[p] == t[p - i]) ++ p;
            extend[i] = p - i;
            front = i;
        }else extend[i] = Next[i - front];
    }
}
string s, t;
int main()
{
    int cas = 0;
    int TAT; scanf("%d", &TAT);
    while(TAT -- )
    {
        cin >> t;
        s = t + t;
        int t_len = t.size(), s_len = s.size();
        GetExtend(s, s_len, t, t_len);
        int _min = 0, _equal = 0, _max = 0;
        for(int i = 0; i < t_len; i ++ )
        {
            if(extend[i] == t_len)
                ++ _equal;
            else
            {
                if(s[i + extend[i]] > t[extend[i]])
                    ++ _max;
                else
                    ++ _min;
            }
        }
        printf("Case %d: %d %d %d\n", ++ cas, _min / _equal, 1, _max / _equal);
    }
    return 0;
}
发布了242 篇原创文章 · 获赞 68 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/weixin_44049850/article/details/104148589
今日推荐