【学习笔记】[AGC044C] Strange Dance

考虑从低到高位建立 3 3 3进制的 trie \text{trie} trie树。然后操作 1 1 1相当于交换每个节点的 1 1 1号儿子和 2 2 2号儿子,当然我们不会老老实实对每个结点交换它的儿子,而是通过打懒标来解决。这也契合了我们只需要输出最终序列的目的。

真正令人头疼的是操作 2 2 2。首先对于根节点,我们应该把 1 1 1号儿子接到 2 2 2号儿子上面, 2 2 2号儿子接到 3 3 3号儿子上面,对于 3 3 3号儿子,我们又要把对应的子树拼接到 0 0 0号儿子对应的位置,我们只用把整颗子树搬过去而不用对子树内部进行额外的递归,因此每次只会递归一边。

复杂度 O ( ∣ T ∣ n + 3 n ) O(|T|n+3^n) O(Tn+3n)

最近似乎总是遇到以前的知识点,但是理解不深入又不会做的情况,看来还是太菜了

#include<bits/stdc++.h>
#define ll long long
#define pb push_back
#define fi first
#define se second
using namespace std;
int n,f[13],res[1000005],tot=1;
string s;
struct trie{
	int son[3];
	int val,lazy;
}t[1000005];
int get(int x,int y){
	return x/f[y]%3;
}
void ins(int x){
	int it=1;
	for(int i=0;i<n;i++){
		int p=get(x,i);
		if(!t[it].son[p])t[it].son[p]=++tot;
		it=t[it].son[p];
	}t[it].val=x;
}
void pushdown(int p){
	if(t[p].lazy){
		swap(t[p].son[1],t[p].son[2]);
		t[t[p].son[0]].lazy^=1,t[t[p].son[1]].lazy^=1,t[t[p].son[2]].lazy^=1;
		t[p].lazy=0;
	}
}
void change(int p){
	if(!p)return;
	pushdown(p);
	int x=t[p].son[0],y=t[p].son[1],z=t[p].son[2];
	t[p].son[1]=x,t[p].son[2]=y,t[p].son[0]=z;
	change(z);
}
int qry(int x){
	int it=1;
	for(int i=0;i<n;i++){
		int p=get(x,i);
		pushdown(it),it=t[it].son[p];
	}return t[it].val;
}
int main(){
	ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	cin>>n>>s;f[0]=1;for(int i=1;i<=12;i++)f[i]=f[i-1]*3;
	for(int i=0;i<f[n];i++)ins(i);
	for(int i=0;i<s.size();i++){
		if(s[i]=='S'){
			t[1].lazy^=1;
		}
		else{
			change(1);
		}
	}for(int i=0;i<f[n];i++)res[qry(i)]=i;
	for(int i=0;i<f[n];i++)cout<<res[i]<<' ';
} 

想了一下,发现我只会 O ( n 4 ) O(n^4) O(n4)的暴力做法。想了想剪枝,感觉过不了,似乎网格图也没啥性质。

然后就自闭了

这题看起来很像一个搜索题,然而又是一个算贡献的题目,那么我们考虑所有点的答案之和加起来,应该是 n 3 n^3 n3级别。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值