SA模板log^2可过但log不过
查看原帖
SA模板log^2可过但log不过
545986
Jerrycyx楼主2025/7/14 20:09

如标题所述,这是直接排序的 O(Nlog2N)O(N \log^2 N) 代码,可以AC

#include <cstdio>
#include <string>
#include <cstring>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;

const int N = 1e6 + 5;
int n; string s;
int sa[N << 1], rk[N << 1];
// SA: the ith suffix
// RK: rank of suffix[i]

int main()
{
	cin >> s; n = s.length();
	iota(sa + 1, sa + n + 1, 1);
	for (int i = 1; i <= n; i++)
		rk[i] = s[i - 1];
	for (int l = 1; l < n; l <<= 1)
	{
		sort(sa + 1, sa + n + 1, [&](int x, int y){
			return rk[x] == rk[y] ? rk[x + l] < rk[y + l] : rk[x] < rk[y];
		});
		static int rkbu[N << 1];
		memcpy(rkbu, rk, sizeof(rk));
		for (int i = 1, idx = 0; i <= n; i++)
		{
			if (rkbu[sa[i]] != rkbu[sa[i - 1]]
			 || rkbu[sa[i] + l] !=rkbu[sa[i - 1] + l]
			) idx++;
			rk[sa[i]] = idx;
		}
	}
	for (int i = 1; i <= n; i++)
		printf("%d ", sa[i]);
	return 0;
}

而这是基数排序的 O(NlogN)O(N \log N) 代码,只能 6363 分,TLE 33 个,MLE 11

#include <cstdio>
#include <string>
#include <vector>
#include <cstring>
#include <numeric>
#include <iostream>
#include <algorithm>
using namespace std;

typedef pair<int,int> PII;
const int N = 1e6 + 5;
int n; string s;
int sa[N << 1], rk[N << 1];
int rge;
// SA[i]: the ith suffix
// RK[i]: rank of suffix[i]

vector<PII> tlt[N], tlt2[N];
void sortsa(int l)
{
	for (int i = 1; i <= n; i++)
		tlt[rk[i + l]].push_back({i, rk[i]});
	for (int i = 0; i <= rge; i++)
	{
		for (PII t : tlt[i])
			tlt2[t.second].push_back(t);
		tlt[i].clear();
	}
	for (int i = 0, idx = 0; i <= rge; i++)
	{
		for (PII t : tlt2[i])
			sa[++idx] = t.first;
		tlt2[i].clear();
	}
	return;
}

int rkbu[N << 1];
void Disc(int l)
{
	memcpy(rkbu, rk, sizeof(rk));
	rge = 0;
	for (int i = 1; i <= n; i++)
	{
		if (rkbu[sa[i]] != rkbu[sa[i - 1]]
		 || rkbu[sa[i] + l] !=rkbu[sa[i - 1] + l]
		) rge++;
		rk[sa[i]] = rge;
	}
	return;
}

int main()
{
	cin >> s; n = s.length();
	iota(sa + 1, sa + n + 1, 1);
	for (int i = 1; i <= n; i++)
		rk[i] = s[i - 1];
	sort(sa + 1, sa + n + 1, [&](int x, int y){
		return rk[x] == rk[y] ? rk[x + 1] < rk[y + 1] : rk[x] < rk[y];
	});
	Disc(1);
	for (int l = 2; l < n; l <<= 1)
	{
		sortsa(l);
		Disc(l);
	}
	for (int i = 1; i <= n; i++)
		printf("%d ", sa[i]);
	return 0;
}

话说基数排序常数那么大吗?少了一个 log\log 反而跑不过了?还是我的写法哪里有问题?请大佬指教!

2025/7/14 20:09
加载中...