jzoj4049-排序【搜索】
生活随笔
收集整理的這篇文章主要介紹了
jzoj4049-排序【搜索】
小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.
正題
題目鏈接:https://jzoj.net/senior/#contest/show/3017/0
題目大意
長度為2n2^n2n的序列,nnn個操作,第iii個可以將序列劃分為2i2^i2i段后交換其中兩段,每個操作只能用一次,求有多少種操作可以使得序列有小到大。
解題思路
每個操作只能一次操作順序不會影響結(jié)果,所以可以假設(shè)從小到大操作,做到第iii個操作時,每個可以被交換的段都必須是已經(jīng)交換好的。
那么假設(shè)現(xiàn)在交換的段長度xxx,那么每段2x2x2x的最多只有兩個不按順序,否則無解,所以我們搜索一下就好了
時間復(fù)雜度O(2nn)O(2^nn)O(2nn)
codecodecode
#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=14; ll n,l,ans,a[1<<N],fac[N]; void dfs(ll dep,ll f){if(dep>n){ans+=fac[f];return;}ll len=1<<dep,h=len/2,z=0,w[4];for(ll i=1;i<=l;i+=len){if(a[i+h]!=a[i]+h) w[++z]=i;if(z>2){return;}}if(!z)dfs(dep+1,f);if(z==1){if(a[w[1]]==a[w[1]+h]+h){for(ll i=w[1];i<w[1]+h;i++)swap(a[i],a[i+h]);dfs(dep+1,f+1);for(ll i=w[1];i<w[1]+h;i++)swap(a[i],a[i+h]);}}if(z==2){if(a[w[1]]+h==a[w[2]]&&a[w[1]+h]+h==a[w[2]+h]){for(ll i=0;i<h;i++)swap(a[w[1]+h+i],a[w[2]+i]);dfs(dep+1,f+1);for(ll i=0;i<h;i++)swap(a[w[1]+h+i],a[w[2]+i]);}if(a[w[2]]+h==a[w[1]+h]&&a[w[1]]+h==a[w[2]+h]){for(ll i=0;i<h;i++)swap(a[w[1]+i],a[w[2]+i]);dfs(dep+1,f+1);for(ll i=0;i<h;i++)swap(a[w[1]+i],a[w[2]+i]);}if(a[w[1]]+h==a[w[2]+h]&&a[w[2]]+h==a[w[1]+h]){for(ll i=0;i<h;i++)swap(a[w[1]+h+i],a[w[2]+h+i]);dfs(dep+1,f+1);for(ll i=0;i<h;i++)swap(a[w[1]+h+i],a[w[2]+h+i]);}if(a[w[2]+h]+h==a[w[1]+h]&&a[w[2]]+h==a[w[1]]){for(ll i=0;i<h;i++)swap(a[w[1]+i],a[w[2]+h+i]);dfs(dep+1,f+1);for(ll i=0;i<h;i++)swap(a[w[1]+i],a[w[2]+h+i]);}} } int main() {scanf("%lld",&n);l=1<<n;fac[0]=1;for(ll i=1;i<=n;i++)fac[i]=fac[i-1]*i;for(ll i=1;i<=l;i++)scanf("%lld",&a[i]);dfs(1,0);printf("%lld",ans); }總結(jié)
以上是生活随笔為你收集整理的jzoj4049-排序【搜索】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: P4781-[模板]拉格朗日插值
- 下一篇: jzoj4050-寻宝游戏【二分,树状数