【学习笔记】[AGC044C] Strange Dance
题目挺绕的,中途甚至怀疑自己是不是读错了题。
瞪了半天一无所获,冷静了一下发现可能是哪个地方想错了,结果又产出了伪算法,根本没想到
trie
\text{trie}
trie树可做。。。
为什么我认为
trie
\text{trie}
trie树不可做?因为我觉得操作
1
1
1用
trie
\text{trie}
trie树做不了。。。
完蛋了。
我们建立 3 3 3进制的 trie \text{trie} trie树, trie \text{trie} trie树上每个点到根节点的路径表示它的位置,同时 trie \text{trie} trie树上每个点记录了一个权值。然后操作 1 1 1相当于交换每个节点的 1 1 1号儿子和 2 2 2号儿子,当然我们不会老老实实对每个结点交换它的儿子,而是通过打懒标来解决。这也契合了我们只需要输出最终序列的目的。
真正令人头疼的是操作
2
2
2。当时觉得进位太复杂了就没往那方面想 我们按从低到高位建立
trie
\text{trie}
trie树,首先对于根节点,我们应该把
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(∣T∣n+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级别。

浙公网安备 33010602011771号