【題解】[USACO20FEB] Swapity Swapity Swap S
阿新 • • 發佈:2021-12-23
有\(n\)頭奶牛從左到右站成一排,初始第\(i\)個位置上為第\(i\)頭奶牛。
每一次晨練包含\(m\)次翻轉操作,翻轉操作形如\((l_i,r_i)\),表示將區間\([l_i,r_i]\)的奶牛翻轉。
現在要進行\(k\)次晨練,求之後每個位置上奶牛的編號。
\(n\le10^5,m\le100,k\le10^9\)。
Solution 1
設\(a_i\)表示位置\(i\)上的奶牛,不難發現我們可以從\(a_i=i\)開始做一次晨練,得到一個對映\(f(x)\)表示\(x\)經過置換後變成什麼。
那麼我們要求的答案也就是\(f^k(x)\)。
這個形式不能不讓人想到快速冪,而顯然這個置換\(f(x)\)
時間複雜度\(O(nm+n\log{k})\)。
code:
#include<bits/stdc++.h> using namespace std; const int maxn=100005; int n,m,K,l[maxn],r[maxn],lp[maxn]; struct seq{ int a[maxn]; } a,f; seq mul(seq x,seq y){//計算置換 seq res; for(int i=1;i<=n;++i) res.a[i]=x.a[y.a[i]]; return res; } seq qpow(seq x,int k){ seq res=x; while(k){ if(k&1) res=mul(res,f); f=mul(f,f); k>>=1; } return res; } int main(){ ios::sync_with_stdio(false); cin.tie(0); cin>>n>>m>>K; for(int i=1;i<=n;++i) a.a[i]=f.a[i]=i; for(int i=1;i<=m;++i){ cin>>l[i]>>r[i]; reverse(f.a+l[i],f.a+r[i]+1); } seq ans=qpow(a,K); for(int i=1;i<=n;++i) cout<<ans.a[i]<<"\n"; return 0; }