P13088 题解

· · 题解

五次操作几乎什么都干不了,所以必须在预处理的时候把东西全部弄好。

现在考虑 p_{q_i} 的置换环数量怎么统计。显然只需要考虑长度 \le 2 的置换环。

计算 \{q_i\} 的逆排列 \{q'_i\}。对于 p_{q_i} 的每个长度为 1 的置换环,都有 p_i=q'_i;对于每个 p_{q_i} 长度为 2 的置换环 (i,j),都有 (p_i,p_j)=(q'_j,q'_i)

发现 (p_i,p_j)=(q'_j,q'_i) 不好处理,但是 \{p_i,p_j\}=\{q'_i,q'_j\} 很好处理。如果两个位置 (i,j) 满足 \{p_i,p_j\}=\{q'_i,q'_j\},那么另外两个位置 (k,l) 也满足 \{p_k,p_l\}=\{q'_k,q'_l\},这样又可以减少一半状态。

对于一个排列,用 16 个 bit 记录对于每个 (i,j) 是否有 p_i=j;然后记录 (0,1),(0,2),(0,3)\{p_i,p_j\}——这需要 18 个 bit,总共是 34 个。

把逆排列也这样做一次,总共恰好 68 个 bit。

现在对于任意一个输入,先把 x_2 右移 34 位拿到逆排列的信息,然后和 x_1 按位与得到 x

现在考虑每一种可能的置换环大小可重集。 $$ \begin{aligned} \{1,1,1,1\}&:c=4+3=7,a=4\\ \{1,1,2\}&:c=2+1=3,a=3\\ \{1,3\}&:c=1,a=2\\ \{2,2\}&:c=0+1=1,a=2\\ \{4\}&:c=0,a=1 \end{aligned} $$ 显然 $a=\mathrm{popcount}(c)+1$,将 $c$ 随便按位或上一个玩意再求 $\mathrm{popcount}$ 就可以做到五步。 ```cpp #include<bits/stdc++.h> using namespace std; #define uint unsigned int #define ull __uint128_t enum{NOT,AND,OR,XOR,LSH,RSH,POPC}; const uint N=1<<16; ostream& operator <<(ostream& out,ull x){ int stk[50],top=0; while(x){stk[++top]=x%10;x/=10;} if (!top) top=1; while(top) out<<stk[top--]; return out; } ull popc(ull x){ ull s=0; for (int i=0;i<68;++i) s+=(x>>i)&1; return s; } struct node{ int type;//NOT AND OR XOR LSH RSH POPCNT bool fl,fr; ull to,L,R; void get(bool& fl,ull& x){ if (fl) cout<<"N ";cout<<x; } void output(){ cout<<to<<' '; if (type==NOT) cout<<"NOT"; if (type==AND) cout<<"AND"; if (type==OR) cout<<"OR"; if (type==XOR) cout<<"XOR"; if (type==LSH) cout<<"LSH"; if (type==RSH) cout<<"RSH"; if (type==POPC) cout<<"POPCNT"; cout<<' ';get(fl,L); if (type&&type<6){ cout<<' '; get(fr,R); } cout<<'\n'; } }; vector<node> ans; void push(ull to,int type,bool fl,ull L,bool fr,ull R){ans.emplace_back((node){type,fl,fr,to,L,R});} void solve(){ push(2,RSH,0,2,1,34); push(1,AND,0,1,0,2); push(1,POPC,0,1,0,0); push(1,OR,0,1,1,8); push(3,POPC,0,1,0,0); } uint id[4][4]; ull get(uint a[]){ ull S=0; for (int i=0;i<3;++i) S|=(1<<i*6+id[a[i]][a[3]]); S<<=16; for (int i=0;i<4;++i) S|=1<<(i*4+a[i]); return S; } void build(){ for (int s=0,i=0;i<4;++i) for (int j=i+1;j<4;++j) id[i][j]=id[j][i]=s++; uint p[4],a[4]; for (int i=0;i<4;++i) p[i]=i; for (int _=0;_<24;++_){ ull A,B; for (int i=0;i<4;++i) a[i]=p[i]; A=get(a); for (int i=0;i<4;++i) a[p[i]]=i; B=get(a); cout<<((B<<34)|A)<<'\n'; next_permutation(p,p+4); } } int main(){ ios::sync_with_stdio(false);cin.tie(0);cout.tie(0); build(); solve(); cout<<ans.size()<<endl; for (auto x:ans) x.output(); return 0; } ```