码迷,mamicode.com
首页 > 编程语言 > 详细

BZOJ 3990 Sdoi2015 排序 DFS

时间:2015-04-16 14:20:22      阅读:152      评论:0      收藏:0      [点我收藏+]

标签:bzoj   bzoj3990   dfs   

题目大意:给定一个长度为2^n的排列,有n个操作,第i个操作为【将序列分成2^(n-i+1)段,每段长2^(i-1),然后任选两段交换】,每个操作最多用一次,求有多少操作序列能把序列排出来

Orz dzy

首先我们很容易发现一个操作序列是否合法与序列的顺序是无关的

因此我们只需要确定某个操作序列中每个操作选不选就行了 那么这类操作序列对答案的贡献就是选择的操作数的阶乘

我们从小到大DFS,对于第i次操作我们将序列分成2^(n-i)段,每段长度2^i

我们找到序列中不是连续递增的段,如果这样的段超过2个,显然就废了

如果没有这样的段,就不需要执行这个操作

如果有一个这样的段,判断将这个段的前半部分和后半部分交换后是否连续递增,如果是就交换然后继续DFS

如果有两个这样的段,判断四种交换情况然后DFS

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define M (1<<12)
using namespace std;
int n;
int a[M];
long long fac[15],ans;
void Swap(int a[],int b[],int len)
{
	int i;
	for(i=0;i<len;i++)
		swap(a[i],b[i]);
}
void DFS(int dpt,int cnt)
{
	if(dpt==n)
	{
		ans+=fac[cnt];
		return ;
	}
	int stack[3]={0,0,0},top=0;
	int i,j,temp=1<<dpt+1;
	for(i=0;i<1<<n;i+=temp)
	{
		if( a[i+(temp>>1)-1]+1!=a[i+(temp>>1)] )
		{
			if(top==2)
				return ;
			stack[++top]=i;
		}
	}
	if(top==0)
	{
		DFS(dpt+1,cnt);
		return ;
	}
	if(top==1)
	{
		i=stack[1];
		if( a[i+temp-1]+1==a[i] )
		{
			Swap(a+i,a+i+(temp>>1),temp>>1);
			DFS(dpt+1,cnt+1);
			Swap(a+i,a+i+(temp>>1),temp>>1);
		}
		return ;
	}
	if(top==2)
	{
		i=stack[1];j=stack[2];
		if( a[i+(temp>>1)-1]+1==a[j+(temp>>1)] && a[j+(temp>>1)-1]+1==a[i+(temp>>1)] )
		{
			Swap(a+i,a+j,temp>>1);
			DFS(dpt+1,cnt+1);
			Swap(a+i,a+j,temp>>1);
			Swap(a+i+(temp>>1),a+j+(temp>>1),temp>>1);
			DFS(dpt+1,cnt+1);
			Swap(a+i+(temp>>1),a+j+(temp>>1),temp>>1);
		}
		if( a[j+(temp>>1)-1]+1==a[i] && a[j+temp-1]+1==a[i+(temp>>1)] )
		{
			Swap(a+i,a+j+(temp>>1),temp>>1);
			DFS(dpt+1,cnt+1);
			Swap(a+i,a+j+(temp>>1),temp>>1);
		}
		if( a[i+(temp>>1)-1]+1==a[j] && a[i+temp-1]+1==a[j+(temp>>1)] )
		{
			Swap(a+j,a+i+(temp>>1),temp>>1);
			DFS(dpt+1,cnt+1);
			Swap(a+j,a+i+(temp>>1),temp>>1);
		}
		return ;
	}
}
int main()
{
	int i;
	cin>>n;
	for(i=0;i<1<<n;i++)
		scanf("%d",&a[i]);
	for(fac[0]=1,i=1;i<=n;i++)
		fac[i]=fac[i-1]*i;
	DFS(0,0);
	cout<<ans<<endl;
	return 0;
}


BZOJ 3990 Sdoi2015 排序 DFS

标签:bzoj   bzoj3990   dfs   

原文地址:http://blog.csdn.net/popoqqq/article/details/45073989

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!