AtCoder Grand Contest 044 C Strange Dance

題意:
3n3^n個數,初始值爲其下標.(下標的範圍是[0,3n)[0,3^n)).
之後有多種操作,操作有兩種:

  1. 每個數在3進制下的1,2互換.
  2. 每個數+1.特別的3n=03^n=0.

非常巧妙的方法:構造一顆012Trie.低位爲Trie樹的淺層.

對於1操作,我們直接給根節點打上一個標記.O(1)O(1).
對於2操作,我們在Trie樹上模擬進位.
對於根節點,我們把0兒子當作新的1兒子,1兒子當作新的2兒子,2兒子當作新的0兒子.
由於出現了進位,我們讓新的0兒子繼續遞歸進行進位.O(n)O(n).

總複雜度:O(3n+Tn)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;
}


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章