3990: [SDOI2015]排序

Time Limit: 20 Sec  Memory Limit: 128 MB
Submit: 336  Solved: 164
[Submit][Status][Discuss]

Description

小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1<=i<=N),第i中操作为将序列从左到右划分为2^{N-i+1}段,每段恰好包括2^{i-1}个数,然后整体交换其中两段.小A想知道可以将数组A从小到大排序的不同的操作序列有多少个,小A认为两个操作序列不同,当且仅当操作个数不同,或者至少一个操作不同(种类不同或者操作位置不同).

  下面是一个操作事例:
  N=3,A[1..8]=[3,6,1,2,7,8,5,4].
  第一次操作,执行第3种操作,交换A[1..4]和A[5..8],交换后的A[1..8]为[7,8,5,4,3,6,1,2].
  第二次操作,执行第1种操作,交换A[3]和A[5],交换后的A[1..8]为[7,8,3,4,5,6,1,2].
  第三次操作,执行第2中操作,交换A[1..2]和A[7..8],交换后的A[1..8]为[1,2,3,4,5,6,7,8].
 

Input

第一行,一个整数N

第二行,2^N个整数,A[1..2^N]
 

Output

一个整数表示答案

 

Sample Input

3
7 8 5 6 1 2 4 3

Sample Output

6

  网上题解都看不懂。。
  只能%hzwer代码。
  
  黄学长:
  每种交换只能用一次。
  我们从小到大DFS,对于第i次操作我们将序列分成2^(n-i)段,每段长度2^i
  我们找到序列中不是连续递增的段,如果这样的段超过2个,显然就废了

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

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

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

  

 #include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath> using namespace std; int a[],n; long long fac[],ans=; void init(){fac[]=;for(int i=;i<=n;i++)fac[i]=fac[i-]*i;} int read()
{
int x=;char ch=getchar();
while(ch<''||ch>'')ch=getchar();
while(ch>=''&&ch<='')x=x*+ch-'',ch=getchar();
return x;
} void swap(int x,int y,int nu)
{
for(int i=x,j=y,nn=;nn<nu;nn++)
swap(a[i+nn],a[j+nn]);
} void DFS(int dep,int sco)
{
if(dep==n)
{
ans+=fac[sco];
return;
}
int temp=<<(dep+),stack[]={,,,},top=;
for(int i=;i<(<<n);i+=temp)
{
if(a[i+(temp>>)-]+!=a[i+(temp>>)])stack[++top]=i+(temp>>)-;
if(top>)return;
}
if(top==)
{
DFS(dep+,sco);
return;
}
else if(top==)
{
if(a[stack[]-(temp>>)+]!=a[stack[]+(temp>>)]+)return;
swap(stack[top]-(temp>>)+,stack[top]+,temp>>);
DFS(dep+,sco+);
swap(stack[top]-(temp>>)+,stack[top]+,temp>>);
return;
}
else
{
if(a[stack[]]+==a[stack[]+]&&a[stack[]]+==a[stack[]+])
{
swap(stack[]-(temp>>)+,stack[]-(temp>>)+,temp>>);
DFS(dep+,sco+);
swap(stack[]-(temp>>)+,stack[]-(temp>>)+,temp>>);
swap(stack[]+,stack[]+,temp>>);
DFS(dep+,sco+);
swap(stack[]+,stack[]+,temp>>);
}
else if(a[stack[]]+==a[stack[]-(temp>>)+]&&a[stack[]+(temp>>)]+==a[stack[]+])
{
swap(stack[]+,stack[]-(temp>>)+,temp>>);
DFS(dep+,sco+);
swap(stack[]+,stack[]-(temp>>)+,temp>>);
}
else if(a[stack[]]+==a[stack[]-(temp>>)+]&&a[stack[]+(temp>>)]+==a[stack[]+])
{
swap(stack[]+,stack[]-(temp>>)+,temp>>);
DFS(dep+,sco+);
swap(stack[]+,stack[]-(temp>>)+,temp>>);
}
return;
}
} int main()
{
n=read();
init();
for(int i=;i<=(<<n);i++)
a[i]=read();
DFS(,);
printf("%lld",ans);
return ;
}

【搜索】BZOJ 3990: 【Sdoi 2015】排序的更多相关文章

  1. BZOJ 3990 [SDOI 2015] 排序 解题报告

    这个题哎呀...细节超级多... 首先,我猜了一个结论.如果有一种排序方案是可行的,假设这个方案是 $S$ . 那么我们把 $S$ 给任意重新排列之后,也必然可以构造出一组合法方案来. 于是我们就可以 ...

  2. [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT)

    [BZOJ 3992] [SDOI 2015] 序列统计(DP+原根+NTT) 题面 小C有一个集合S,里面的元素都是小于质数M的非负整数.他用程序编写了一个数列生成器,可以生成一个长度为N的数列,数 ...

  3. BZOJ 3990: [SDOI2015]排序(搜索+剪枝)

    [SDOI2015]排序 Description 小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1< ...

  4. BZOJ 3992 [SDOI 2015] 序列统计 解题报告

    这个题最暴力的搞法就是这样的: 设 $Dp[i][j]$ 为前 $i$ 个数乘积为 $j$ 的方案数. 转移的话就不多说了哈... 当前复杂度 $O(nm^2)$ 注意到,$M$ 是个质数,就说明 $ ...

  5. BZOJ 3993 [SDOI 2015] 星际战争 解题报告

    首先我们可以二分答案. 假设当前二分出来的答案是 $Ans$ ,那么我们考虑用网络流检验: 设武器为 $X$,第 $i$ 个武器的攻击力为 $B_i$: 设机器人为 $Y$,第 $i$ 个机器人的装甲 ...

  6. [BZOJ 3992] [SDOI 2015] 序列统计

    Description 传送门 Solution [一] 设 \(f[i][j]\) 表示前 \(i\) 个数的乘积在模 \(p\) 意义下等于 \(j\) 的方案数,有 \[ f[i][j]=\su ...

  7. Mobius反演与积性函数前缀和演学习笔记 BZOJ 4176 Lucas的数论 SDOI 2015 约数个数和

    下文中所有讨论都在数论函数范围内开展. 数论函数指的是定义域为正整数域, 且值域为复数域的函数. 数论意义下的和式处理技巧 因子 \[ \sum_{d | n} a_d = \sum_{d | n} ...

  8. [BZOJ 1879][SDOI 2009]Bill的挑战 题解(状压DP)

    [BZOJ 1879][SDOI 2009]Bill的挑战 Description Solution 1.考虑状压的方式. 方案1:如果我们把每一个字符串压起来,用一个布尔数组表示与每一个字母的匹配关 ...

  9. [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机

    [LOJ 2134][UOJ 132][BZOJ 4200][NOI 2015]小园丁与老司机 题意 给定平面上的 \(n\) 个整点 \((x_i,y_i)\), 一共有两个问题. 第一个问题是从原 ...

  10. [LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会

    [LOJ 2133][UOJ 131][BZOJ 4199][NOI 2015]品酒大会 题意 给定一个长度为 \(n\) 的字符串 \(s\), 对于所有 \(r\in[1,n]\) 求出 \(s\ ...

随机推荐

  1. SQL_从星期一到星期六自动打卡SQL代码

    create proc sp_MarkAutoKQ as begin ) ---创建两个变量,接收当前时间和当天是星期几 set @dateA=getdate() ---获取当前时间 set @dat ...

  2. js前端防止默认表单提交

    代码如下: document.forms[0].onsubmit=function(){return false;};

  3. Cocos开发中Visual Studio下libcurl库开发环境设置

    我们介绍一下win32中Visual Studio下libcurl库开发环境设置.Cocos2d-x引擎其实已经带有为Win32下访问libcurl库,Cocos2d-x 3.x中libcurl库文件 ...

  4. 关于百度编辑器UEditor(1.4.3)在C#.NET中的应用实例

    首先去百度UEditor官网下载 1.4.3 .net版本 http://ueditor.baidu.com/build/build_down.php?n=ueditor&v=1_4_3-ut ...

  5. YII Framework 1.0运行时序图分析过程

  6. 【转载】茶叶蛋干货!《超容易的Linux系统管理入门书》(连载十)进行动态主机配置DHCP

    使用动态主机配置协议DHCP(Dynamic Host Configuration Protocol)则可以避免网络参数变化后一些繁琐的配置,客户端可以从DHCP服务端检索相关信息并完成相关网络配置, ...

  7. JDK中工具类的使用

    JDK中内置了很多常用的工具类,且多以“s”结尾,如:集合工具类Collections,数组工具类Arrays,对象工具类Objects,文件工具类Files,路径工具类Paths,数学工具类Math ...

  8. 实现android支持多线程断点续传下载器功能

    多线程断点下载流程图: 多线程断点续传下载原理介绍: 在下载的时候多个线程并发可以占用服务器端更多资源,从而加快下载速度手机端下载数据时难免会出现无信号断线.电量不足等情况,所以需要断点续传功能根据下 ...

  9. Linux 通过 shell 脚本修改密码

    交互方式修改密码 1. ssh 远程到主机: 2. 切换到root账号: [一般都是切换到root进行密码修改,如果普通用户修改自己的密码,要输入原密码,然后新密码要满足复杂度才OK]: 3. pas ...

  10. SystemFile

    header('Content-Type:text/html; charset = utf-8'); 1. echo "<pre/>";echo __FILE__.&q ...