Codeforces Round #778 (Div. 1 + Div. 2, based on Technocup 2022 Final Round) F Minimal String Xoration CF1654F

A-E 都还是比较简单的。

首先,容易想到的,异或上 \(2^k\),相当于以 \(2^{k+1}\) 的长度分块,然后每一块对半切,然后交换左右部分。

我的想法是由于这个交换的性质,也许我们可以尝试着快速计算哈希值。

显然有 \(h(x,2^k,i)=h(x,2^{k-1},i)+h(x \ \text{xor} \ 2^{k-1},2^{k-1},i)\)\(h(x,k,i)\) 表示异或上 \(x\),长度为 \(2^k\),左端点为 \(i\),这个区间的哈希值。

不过你现在好像必须 \(O(n^2)\) 以上取计算每个状态!

于是你考虑能否交换,使得查询区间成为前缀区间,然后我们只记录前缀区间的哈希值即可。

显然你可以写一份暴力,每次判断查询区间是否与 0 分居两侧,是的话就换。写出来后发现 \(x=x\ \text{xor} \ i\) 即可。

#pragma GCC optimize("Ofast","-funroll-loops")
#pragma GCC target("sse4.1","sse4.2","ssse3","sse3","sse2","sse","avx2","avx","popcnt","tune=native")
#include <bits/stdc++.h>
//#define int long long
#define ull unsigned long long
#define pb push_back
using namespace std;
const ull base=19260817;
const int N=(1<<18)+5;
//map<int,ull>mp[N][19];
ull h[N][19];
ull v[26],pw[N];
char s[N];
int n,m,M;
mt19937 RAND(time(0));

ull cal(ull x) {
	return x*x*x*x+2*x*x*x+3*x*x+4*x+7+M;
}

ull dfs(int x,int k,int i) { //i\to 0
//	for(int t=1;t<=m+1;t++) {
//		for(int p=m;p>=0;p--) {
//			int l=(1<<p),r=(1<<(p+1))-1;
////			if(l<=i&&(i+(1<<k)-1)<=r) {
//			if((i>>p)&1) {
//				x^=(1<<p);
//				i-=l;
//			}
//		}
		x^=i;
//		cout<<i<<" "<<h[x][k]<<'\n';
		return h[x][k];
//	}
}

ull get(int x,int l,int r) {
	int qwq=(r-l+1),nw=l; ull res=0;
	for(int i=m;i>=0;i--) {
//		cout<<nw<<" "<<res<<" "<<l<<" "<<r<<'\n';
		if((qwq>>i)&1) {
			res=res*pw[(1<<i)]+dfs(x,i,nw);
			nw+=(1<<i);
		}
	}
	return res;
//	ull res=0;
//	for(int i=l;i<=r;i++) res=res*base+s[i^x]-'a';
//	cout<<x<<" "<<l<<" "<<r<<" "<<res<<'\n';
//	return res;
}

bool cmp(int x,int y) {
	int l=0,r=n-1,res=-1;
	while(l<=r) {
		int mid=(l+r)>>1;
		if(get(x,0,mid)==get(y,0,mid)) res=mid,l=mid+1;
		else r=mid-1;
	}
	
	if(res==n-1) return 0;
	++res;
//	cout<<x<<" "<<y<<" "<<res<<" "<<s[res^x]<<" "<<s[res^y]<<'\n';
	if(s[res^x]<s[res^y]) return 1;
	return 0;
}

signed main() {
	cin.tie(0); ios::sync_with_stdio(false);
	cin>>m>>s; n=(1<<m);
	M=RAND()%10;
	for(int i=0;i<26;i++) v[i]=cal(cal(cal(cal(cal((ull)i)))));
	pw[0]=1;
	for(int i=1;i<=n;i++) pw[i]=pw[i-1]*base;
	for(int i=0;i<n;i++) {
//		for(int j=0;j<n;j++) {
//			h[i][0][j]=v[s[j^i]-'a'];
//		}
		h[i][0]=v[s[i]-'a'];
	}
	for(int k=1;k<=m;k++) {
		int len=(1<<k);
		for(int x=0;x<n;x++) {
//			for(int i=0;i<n;i+=len) {
//				h[x][k][i]=h[x][k-1][i]*pw[len/2]+h[x^(1ll<<(k-1))][k-1][i];   
//			}
			h[x][k]=h[x][k-1]*pw[len/2]+h[x^(1<<(k-1))][k-1];
		}
	}
	int ans=0;
	for(int i=1;i<n;i++) {
		if(cmp(i,ans)==1) 
//		{
//			for(int j=0;j<=m;j++) map<int,ull>().swap(mp[ans][j]);
			ans=i;
//		} else {
//			for(int j=0;j<=m;j++) map<int,ull>().swap(mp[i][j]);
//		}
	}
//	cout<<ans<<'\n';
	for(int i=0;i<n;i++) cout<<(char)(s[i^ans]);
	return 0;
} 
posted @ 2022-11-04 16:14  FxorG  阅读(20)  评论(0编辑  收藏  举报