AtCoder Grand Contest 044 C Strange Dance

题意:
3 n 3^n 个数,初始值为其下标.(下标的范围是 [ 0 , 3 n ) [0,3^n) ).
之后有多种操作,操作有两种:

  1. 每个数在3进制下的1,2互换.
  2. 每个数+1.特别的 3 n = 0 3^n=0 .

非常巧妙的方法:构造一颗012Trie.低位为Trie树的浅层.

对于1操作,我们直接给根节点打上一个标记. O ( 1 ) O(1) .
对于2操作,我们在Trie树上模拟进位.
对于根节点,我们把0儿子当作新的1儿子,1儿子当作新的2儿子,2儿子当作新的0儿子.
由于出现了进位,我们让新的0儿子继续递归进行进位. O ( n ) O(n) .

总复杂度: O ( 3 n + T n ) O(3^n+|T|n) .

这个方法的巧妙之处在于它把子树末位相同的规制为相同类,这样就可以对每一位进行快速处理.
Trie树本质上对数据进行了打包.

#include<map>
#include<queue>
#include<cmath>
#include<bitset>
#include<cstdio>
#include<vector>
#include<cctype>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#define fi first
#define se second
#define lc (x<<1)
#define rc (x<<1|1)
#define gc getchar()
#define mk make_pair
#define pi pair<int,int>
#define pb push_back
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int N=14,M=797171,T=2e5+10;
template<class o>void qr(o&x) {
	char c=gc;int f=1;x=0;
	while(!isdigit(c)){if(c=='-')f=-1;c=gc;}
	while(isdigit(c))x=x*10+c-'0',c=gc;
	x*=f;
}
template<class o>void qw(o x) {
	if(x/10)qw(x/10);
	putchar(x%10+'0');
}
template<class o> void pr1(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x); putchar(' ');
}
template<class o>void pr2(o x) {
	if(x<0)x=-x,putchar('-');
	qw(x);puts("");
}

int trie[M][3],ed[M],p[M],n,cnt=1,tot,f[N]; 
char s[T]; bool v[M];

void insert(int x) {
	int p=1;
	for(int i=1;i<=n;i++) {
		int c=x%3; x/=3;
		if(!trie[p][c]) trie[p][c]=++cnt;
		p=trie[p][c];
	}
	ed[p]=++tot;
}

void lazy(int x) {
	if(v[x]) {
		v[x]=0;
		int &y=trie[x][1],&z=trie[x][2];
		swap(y,z); 
		v[trie[x][0]]^=1; v[y]^=1; v[z]^=1;
	}
}

void add(int x) {
	if(ed[x]) return ;
	lazy(x);
	int a=trie[x][0],b=trie[x][1],c=trie[x][2];
	trie[x][0]=c; trie[x][1]=a; trie[x][2]=b;
	add(c);
}

void dfs(int x,int y,int d) {//节点编号,真实值,深度 
	if(ed[x]) {p[ed[x]]=y; return ;} lazy(x);
	for(int i=0;i<=2;i++) dfs(trie[x][i],y+i*f[d],d+1);
}

int main() {	
	qr(n); scanf("%s",s+1);
	f[0]=1; for(int i=1;i<=n;i++) f[i]=f[i-1]*3;
	for(int i=0;i<f[n];i++) insert(i);
	for(int i=1;s[i];i++) 
		if(s[i]=='S') v[1]^=1;
		else add(1);
	dfs(1,0,0);	for(int i=1;i<=tot;i++) pr1(p[i]);
	return 0;
}


猜你喜欢

转载自blog.csdn.net/qq_42886072/article/details/106333298