牛客网暑期ACM多校训练营(第三场)E Sort String [字符串 + hash函数 / 字符串 + kmp]

版权声明: https://blog.csdn.net/weixin_39792252/article/details/82257211

题目:要求将前i个字符放到后面字符串的后面形成一个新串s_{i},如果s_{i} = s_{j}ij就放在一组,最后将每一组按照字典序排序,每一组的个数就是这组的一个标号。 

思路1:将字符串s复制一下s+s,那么用字符串hash,只要维护之前有没有出现过就可以啦,但是非常卡时间!!!

 字符串hash的常见方法:

*111111......  unsigned long long 相当于对2^{64}取模

unsigned long long hash[maxn], p[maxn];
char s[maxn];

void Hash(int x) {
	p[0] = 1;
	h[0] = 0;
	for(int i = 1; i <= x; i++) {
		p[i] = p[i-1]*seed;
		h[i] = h[i-1]*seed + s[i];
	}
}

unsigned long long gethash(int l, int r) { 
	return h[r] - h[l-1]*p[r - l + 1];
}

 *222222......single hash(一般seed取6-8位的素数,mod取1e9+7 || 1e9 + 9)

inline void Hash(int x) {
	p[0] = 1;
	h[0] = 0;
	for(int i = 1; i <= x; i++) {
		p[i] = (p[i-1]*seed)%mod;
		h[i] = (h[i-1]*seed%mod + s[i]-'a')%mod;
	}
}

inline ll gethash(int l, int r) {
	return (h[r] - h[l-1]*p[r - l + 1]%mod + mod)%mod;
}

*333333......double hash(mod1取1e9+7 || mod2取1e9+9)

hash1[i] = (hash1[i-1]*p + idx(s[i]))%mod1;

hash2[i] = (hash2[i-1]*p + idx(s[i]))%mod2;

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<vector>
#include<unordered_map>
#include<algorithm>
#define ll long long
#define ull unsigned long long
#define inf 0x3f3f3f
#define seed 131
using namespace std;
const int maxn = 2e6+5;
 
int len;
char s[maxn];
ull p[maxn], h[maxn];
 
inline void Hash(int x) {
    p[0] = 1;
    h[0] = 0;
    for(int i = 1; i <= x; i++)
    {
        p[i] = p[i-1]*seed;
        h[i] = h[i-1]*seed + s[i];
    }
}
 
inline ull  gethash(int l, int r) {
    return h[r] - h[l-1]*p[r - l + 1];
}
 
vector<int> v[maxn];
unordered_map<ull, int> mp;
 
 
int main()
{
    //freopen("in.txt", "r", stdin);
    while(scanf("%s", s+1) != EOF) {
        len = strlen(s+1);
        for(int i = 1; i <= len; i++) s[i+len] = s[i];
        Hash(2*len);
        int num = 0;
        for(int i = 1; i <= len; i++) {
            ull ans = gethash(i, i+len-1);
            if(mp[ans] == 0) {
                mp[ans] = ++num;
                v[num].push_back(i-1);
            } else {
                v[mp[ans]].push_back(i-1);
            }
        }
        printf("%d\n", num);
        for(int i = 1; i <= num; i++)
        {
            printf("%d", v[i].size());
            for(int j = 0; j < v[i].size(); j++) printf(" %d", v[i][j]);
            printf("\n");
        }
    }
    return 0;
}

第二种思路是:利用KMP的next数组求字符串的最小循环节,正确把握next数组的本质

具体暂时留坑吧。。。。

扫描二维码关注公众号,回复: 3127010 查看本文章

代码:

#include <bits/stdc++.h>
using namespace std;

const int maxn = 1e6+10;
char str[maxn];
int nex[maxn];

void get_next(int len) {
    int j = -1;
    nex[0] = -1;
    for(int i = 1; i <= len; i++) {
        while(j>-1&&str[j+1] != str[i]) j = nex[j];
        if(str[j+1] == str[i]) j++;
        nex[i] = j;
    }

    //for(int i = 0; i < len; i++) cout << nex[i] << endl;
}


int main(void) {
    cin >> str;
    int len = strlen(str);
    get_next(len);
    int x = len - nex[len-1] - 1;
    if (len % x != 0) {
        printf("%d\n", len);
        for(int i = 0; i < len; i++) printf("1 %d\n", i);
    }
    else {
        printf("%d\n", x);
        for(int i = 0; i < x; i++) {
            printf("%d", len / x);
            for(int j = i; j < len; j += x) printf(" %d", j);
            printf("\n");
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_39792252/article/details/82257211
今日推荐