CF1654F Minimal String Xoration 题解
题目链接
题目解法
咋想到的?咋想到的?
这类题我能想到的有两种解法:逐位确定,两两比较。但我都不会做
题解的出发点是倍增,可以说是一个完全不同的思路
令 \(str_{i,j}\) 表示下标异或的数为 \(i\),异或之后的序列的第 \(0\) 到 \(2^j-1\) 位的字符串
\(rk_{i,j}\) 表示 \(str_{i,j}\) 的排名
有一个很重要的性质是:\(str_{i,j}=str_{i,j-1}+str_{i\oplus{2^{j-1}},j-1}\)
这启发我们用倍增的思想解决问题
对每个 \(j\) 用类似求 \(sa\) 的方式 \(sort\) 一遍然后求新的排名即可
时间复杂度 \(O(n^22^n)\)
#include <bits/stdc++.h>
#define F(i,x,y) for(int i=(x);i<=(y);i++)
#define DF(i,x,y) for(int i=(x);i>=(y);i--)
#define ms(x,y) memset(x,y,sizeof(x))
#define SZ(x) (int)x.size()-1
#define all(x) x.begin(),x.end()
#define pb push_back
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
typedef pair<int,int> pii;
template<typename T> void chkmax(T &x,T y){ x=max(x,y);}
template<typename T> void chkmin(T &x,T y){ x=min(x,y);}
inline int read(){
int FF=0,RR=1;
char ch=getchar();
for(;!isdigit(ch);ch=getchar()) if(ch=='-') RR=-1;
for(;isdigit(ch);ch=getchar()) FF=(FF<<1)+(FF<<3)+ch-48;
return FF*RR;
}
const int N=18;
int n,rk[1<<N],id[1<<N],nwrk[1<<N];
char str[1<<N];
int main(){
n=read();scanf("%s",str);
int full=(1<<n)-1;
F(i,0,full) rk[i]=str[i]-'a';
F(i,0,n-1){
F(j,0,full) id[j]=j;
sort(id,id+full+1,[&](int x,int y){ return pair{rk[x],rk[x^(1<<i)]}<pair{rk[y],rk[y^(1<<i)]};});
nwrk[id[0]]=0;int cur=0;
F(j,1,full){
int x=id[j],y=id[j-1];
nwrk[x]=(pair{rk[x],rk[x^(1<<i)]}==pair{rk[y],rk[y^(1<<i)]})?cur:++cur;
}
F(j,0,full) rk[j]=nwrk[j];
}
F(i,0,full) putchar(str[i^id[0]]);puts("");
return 0;
}

浙公网安备 33010602011771号