牛客多校第3场 E.Sort String(字符串哈希)

题意:根据原字符串构造新串,对于原字符串从0~|S|-1,i从0开始,从i到最后的子串放到从0到i-1子串的前面。对于这些新构造的子串,从0开始编号,将相同的新字符串们归为一组,
输出一共有多少组,每组有多少个新字符串,以及新字符串的编号。 按字典序输出

思路:这题可以采用字符串哈希暴力来求解.对于将后面的值移动到前面形成的新串,我们可以有两种方法来处理.

第一种简单粗暴,直接将字符串长度扩大一倍,那么就变成了十分常规的求解区间字符串哈希值,然后就是一一比较判断是不是第一次出现的即可.

#include <bits/stdc++.h>
#include <cmath>
#include <unordered_map>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <cctype>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ull MOD = 1e9 + 7;
const int maxn = 2e6 + 5;
const int seed = 131;
char a[maxn];
ull p[maxn];
ull h[maxn];//类似于前缀和
void Hash(int len) {
    p[0] = 1;
    h[0] = 0;
    for(int i = 1; i <= len; i++) {
        p[i] = p[i - 1] * seed ;
        h[i] = h[i - 1] * seed + a[i];
    }
}
ull get_has(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() {
    scanf("%s", a + 1);
    int n = strlen(a + 1);
    for(int i = 1; i <= n; i++) {
        a[i + n] = a[i];
    }
    Hash(n * 2);
    int num = 0;

    for(int i = 1; i <= n; i++) {
        ull ans = get_has(i, i + n - 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++) {
            if(j != v[i].size() - 1) printf("%d ", v[i][j]);
            else printf("%d\n", v[i][j]);
        }
    }
    return 0;
}

第二种方法更加巧妙一点,我们考虑将后面的串移动到前面,我们可以理解为区间的移动,那么我们就可以推出一个公式,,假设前面的串是 [ 1 , x ] ,对应哈希值是 s t ,后面的串是 [ x + 1 , n ] ,对应的哈希值是 l a ,那么将后面的串移动到前面形成的新串的哈希值就可以理解为 s t + l a p x ,公式不难推,手动模拟一下就会.

#include <bits/stdc++.h>
#include <cmath>
#include <unordered_map>
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>
#include <vector>
#include <stack>
#include <set>
#include <cctype>
#define eps 1e-8
#define INF 0x3f3f3f3f
#define PI acos(-1)
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ull MOD = 1e9 + 7;
const int maxn = 1e6 + 5;
const int seed = 131;
char a[maxn];
ull p[maxn];
ull h[maxn];
void Hash(char *s) {
    p[0] = 1;
    h[0] = 0;
    int len = strlen(s + 1);
    for(int i = 1; i <= len; i++) {
        p[i] = p[i - 1] * seed ;
        h[i] = (h[i - 1] * seed + s[i]) ;
    }
}
ull get_has(int l, int r) {
    return (h[r] - h[l - 1] * p[r - l + 1] ) ;
}
unordered_map<ull, int>mp;
vector<int>v[maxn];
int main() {
    scanf("%s", a + 1);
    Hash(a);
    int n = strlen(a + 1);
    int num = 0;
    mp[get_has(1, n)] = ++num;
    v[num].push_back(0);
    for(int i = 1; i < n; i++) {
        ull st = get_has(1, n - i);
        ull la = get_has(n - i + 1, n);
        ull ans = (st  + la * p[n - i]) ;
        if(mp[ans] == 0) {
            mp[ans] = ++num;
            v[num].push_back(i);
        } else {
            v[mp[ans]].push_back(i);
        }
    }
    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++) {
            if(j != v[i].size() - 1) printf("%d ", v[i][j]);
            else printf("%d\n", v[i][j]);
        }
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/81240855