题解 [CF1654F] Minimal String Xoration

传送门

后缀数组(倍增排序?)还能这么玩,长见识了

发现这个异或是作用在下标上的,所以基本上没什么可以用的贪心策略
那么直接说正解:
\(f(s, x)=s_{i\oplus x}\)
那么若已知所有的 \(x\)\(f(s, x)\)\([0:2^{k-1}-1]\) 为关键字的排序结果,可以推出以 \([0:2^k-1]\) 为关键字的排序结果
具体地,考虑 \(f(s, x)[2^{k-1}:2^k-1]=f(s, x\oplus 2^{k-1})[0, 2^{k-1}-1]\) 就可以了
那么复杂度是 \(O(n2^n)\)

点击查看代码
#include <bits/stdc++.h>
using namespace std;
#define INF 0x3f3f3f3f
#define N 300010
#define ll long long
//#define int long long

int n, m=256;
char s[N];
int cnt[N], sa[N], rk[N], oldrk[N<<1], id[N], px[N];
inline bool cmp(int a, int b, int w) {return oldrk[a]==oldrk[b]&&oldrk[a^w]==oldrk[b^w];}

signed main()
{
	scanf("%d%s", &n, s);
	n=1<<n;
	for (int i=0; i<n; ++i) ++cnt[rk[i]=s[i]];
	for (int i=1; i<=m; ++i) cnt[i]+=cnt[i-1];
	for (int i=0; i<n; ++i) sa[--cnt[rk[i]]]=i;
	for (int w=1,p; w<n; w<<=1,m=p) {
		p=0;
		for (int i=0; i<n; ++i) id[p++]=sa[i]^w;
		for (int i=0; i<=m; ++i) cnt[i]=0;
		for (int i=0; i<n; ++i) ++cnt[px[i]=rk[id[i]]];
		for (int i=1; i<=m; ++i) cnt[i]+=cnt[i-1];
		for (int i=n-1; ~i; --i) sa[--cnt[px[i]]]=id[i];
		for (int i=0; i<n; ++i) oldrk[i]=rk[i];
		rk[sa[0]]=p=1;
		for (int i=1; i<n; ++i) rk[sa[i]]=cmp(sa[i], sa[i-1], w)?p:++p;
		if (p==n) break;
	}
	int x=sa[0];
	for (int i=0; i<n; ++i) printf("%c", s[i^x]);
	printf("\n");

	return 0;
}
posted @ 2022-03-30 10:27  Administrator-09  阅读(4)  评论(0编辑  收藏  举报