牛客网暑期ACM多校训练营(第三场)E Sort String

本文介绍了一种通过寻找字符串中的循环节来解决特定问题的方法。该问题要求将字符串进行特定变换并分组,最终输出每组的循环节长度及对应索引。文章详细解释了解决方案的过程,并提供了一个使用KMP算法求解循环节长度的C++实现。
摘要由CSDN通过智能技术生成

5. Eddy likes to play with string which is a sequence of characters. One day, Eddy has played with a string S
for a long time and wonders how could make it more enjoyable. Eddy comes up with following procedure:
1. For each i in [0,|S|-1], let S i be the substring of S starting from i-th character to the end followed by the
substring of first i characters of S. Index of string starts from 0.
2. Group up all the S i . S i and S j will be the same group if and only if S i =S j .
3. For each group, let L j be the list of index i in non-decreasing order of S i in this group.
4. Sort all the L j by lexicographical order.
Eddy can't find any efficient way to compute the final result. As one of his best friend, you come to help him
compute the answer!
输入描述:
Input contains only one line consisting of a string S.
1≤ |S|≤ 10 6
S only contains lowercase English letters(i.e. ).
输出描述:
First, output one line containing an integer K indicating the number of lists.
For each following K lines, output each list in lexicographical order.
For each list, output its length followed by the indexes in it separated by a single space.
示例1:
输入
abab
输出
2
2 0 2
2 1 3
示例2:
输入
deadbeef
输出
8
1 0
1 1
1 2
1 3
1 4
1 5
1 6
1 7

题目手动复制,可能有点不一样

题解:这道题说把把前i个移到尾 在分个组 其实就是无非找个循环节,输出循环节长度,总长度除以循环节长度,从一个位置开始不断加循环节长度,我一开始直接把全部东西塞到set里求循环节长度,爆内存过55% 然后用kmp求循环节长度,结果过95%然后就蒙逼了,无可奈何最后加了个输入输出挂 结果就过了 都这么骚的吗!!!

#include<bits/stdc++.h>
 
using namespace std;
const double PI = acos(-1.0);
typedef long long ll;
#define rep(i, a, n) for (int i=a;i<n;i++)
#define per(i, a, n) for (int i=n-1;i>=a;i--)
#define clr(x) memset(x,0,sizeof(x))
const int INF = 0x3f3f3f3f;
char b[1000005];
int Next[1000005];
int n;
namespace io {
    const int L = (1 << 21) + 1;
    char ibuf[L], *iS, *iT, obuf[L], *oS = obuf, *oT = obuf + L - 1, c, st[55];
    int f, tp;
#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,L,stdin),(iS==iT?EOF:*iS++)):*iS++)
 
    inline void flush() {
        fwrite(obuf, 1, oS - obuf, stdout);
        oS = obuf;
    }
 
    inline void putc(char x) {
        *oS++ = x;
        if (oS == oT) flush();
    }
 
    template<class I>
    inline void gi(I &x) {
        for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) if (c == '-') f = -1;
        for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15);
        x *= f;
    }
 
    template<class I>
    inline void print(I x) {
        if (!x) putc('0');
        if (x < 0) putc('-'), x = -x;
        while (x) st[++tp] = x % 10 + '0', x /= 10;
        while (tp) putc(st[tp--]);
    }
 
    inline void gs(char *s, int &l) {
        for (c = gc(); c < 'a' || c > 'z'; c = gc());
        for (l = 0; c <= 'z' && c >= 'a'; c = gc()) s[l++] = c;
        s[l] = 0;
    }
 
    inline void ps(const char *s) { for (int i = 0, n = strlen(s); i < n; i++) putc(s[i]); }
 
    struct IOFLUSHER {
        ~IOFLUSHER() { flush(); }
    } _ioflusher_;
};
 
void SetNext()//子串的next数组,如果只看代码的话,很难得出值的确定方法。
{
    int i = 0, j = -1;
    Next[0] = -1;
    while (i < n) {
        if (j == -1 || b[i] == b[j])//b为模式数组
        {
            i++;
            j++;
            Next[i] = j;
        } else
            j = Next[j];
    }
}
 
int main() {
//    本地测试
	#ifdef ONLINE_JUDGE
	#else
    freopen("C://Users//yan//Desktop//in.txt","r",stdin);
	//    freopen("C://Users//yan//Desktop//out.txt","w",stdout);
	#endif
    ios::sync_with_stdio(false);//取消同步
    std::cin.tie(0);//解除cin与cout的绑定,进一步加快执行效率。
    io::gs(b, n);
    SetNext();
    int sum = n - Next[n];
    int ssum = n / sum;
    io::print(sum);
    io::putc('\n');
//    cout << sum << endl;
    for (int i = 0; i < sum; i++) {
        io::print(ssum);
//        cout << ssum;
        for (int j = i; j < n; j = j + sum) {
            io::putc(' ');
            io::print(j);
//            cout << " " << j;
        }
//        cout << endl;
        io::putc('\n');
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值