1. 程式人生 > 其它 >【題解】[USACO20FEB] Swapity Swapity Swap S

【題解】[USACO20FEB] Swapity Swapity Swap S

\(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)\)

具有結合律,也就是說\(f^{2r}(x)=f^r(f^r(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;
}