agc044 c Strange Dance

Problem statement
首先要发现一个性质:
如果一个三进制数如下:
. . . . . . 0
它加1后变为
. . . . . . 1
所以
…0 +1=…1
…1 +1=…2
…2 +1=…10
…10+1=…11
可以建立一棵trie:

                    s
             0      1       2
          0 1 2   0 1 2   0 1 2
          ......................

其中每一个叶子的值都是从s走到这个叶子所够成的三进制数(从上往下代表三进制的低位到高位!)
所以+1的操作就是从s开始把每一条边上的值都+1 并%3.
然后再递归原来值为2的边指向的儿子节点。这样就可以再 O ( n ) O(n) O(n) 的时间内完成+1操作。
然后 1 − > 2 , 2 − > 1 1->2,2->1 1>2,2>1的操作可以再每一个trie的节点上打上lazy tag 。如果处理到就把1的边上的值变成2,2的边的值变为1,再push_down就行了.
总复杂读 O ( n ∗ ∣ T ∣ ) O(n*|T|) O(nT)
代码:

#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define KEEP while(1)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define debug_pair(A) cerr<<A.FIR<<" "<<A.SEC<<endl;
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
typedef pair<mp,mp> superpair;
int N,LOGN,n;

struct node{
	int val;
	vector<mp> sons;
	bool flag;
	void push_down(){
		if(!flag||sons.empty()){
			return;
		}
		flag=0;
		int i1,i2;
		rep(i,3)
			if(sons[i].FIR==1) i1=i;
		rep(i,3)
			if(sons[i].FIR==2) i2=i;
		swap(sons[i1].FIR,sons[i2].FIR);
	} 
}trie[2000000];
void gao(int index){
	trie[index].flag^=1;	
}
int cnt=1;
int b[13];
void build(int now,int depth,int val){
	if(depth==LOGN+1) {
//		cout<<now<<" "<<val<<endl;
		trie[now].val=val;
		return;
	}
	trie[now].sons.PB(II(0,++cnt));
	build(cnt,depth+1,val);
	trie[now].sons.PB(II(1,++cnt));
	build(cnt,depth+1,val+b[-1+depth]);
	trie[now].sons.PB(II(2,++cnt));	
	build(cnt,depth+1,val+b[-1+depth]*2);
}
void modify(int now){
//	cout<<"!" <<now<<endl;
	if(trie[now].sons.empty()) return;
	if(trie[now].flag){
	trie[now].push_down();
		rep(i,3)
		gao(trie[now].sons[i].SEC);
	}
	rep(i,3)
	{
		trie[now].sons[i].FIR++;
		trie[now].sons[i].FIR%=3;
		if(!trie[now].sons[i].FIR){
			modify(trie[now].sons[i].SEC);
		}
	}
}
int res[600000];
void recover(int now,int pos,int depth){
	if(trie[now].sons.empty()){
		res[trie[now].val]=pos;
	}
	else{	
		if(trie[now].flag){
		
		trie[now].push_down();
			rep(i,3)
			gao(trie[now].sons[i].SEC);
		}
		rep(i,3){
			recover(trie[now].sons[i].SEC,pos+b[depth-1]*trie[now].sons[i].FIR,depth+1);
		}
	}
}
int main(){
	fastio;
	cin>>N;
	n=1;
	rb(i,1,N) n*=3;
	b[0]=1;
	rb(i,1,N)
		b[i]=b[i-1]*3;
	LOGN=N;
	N=n;
	build(1,1,0);
	string T="";
	cin>>T;
	rep(INDEX,T.length()){
		bool ty=(T[INDEX]=='S');
		if(ty){
			trie[1].flag^=1;
		}
		else{
			modify(1);
		}
	}
	recover(1,0,1);
	rb(i,0,N-1)
		cout<<res[i]<<" ";
	return 0;
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值