题目传送门


题目描述

小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].


有关题目描述的说明

说实话,一开始真没看懂题。

其实,大致意思就是说,每次把序列分成${2}^{N-i+1}$个长度为${2}^{i-1}$的块,每次可以选择其中两块交换。

需要注意的两点就是:

  1.每种操作只能使用一次。

  2.不是说所有长度为2(i-1)的都行,举个例子:假设长度为2,那么每一块就是{1,2},{3,4},{5,6},……,而{2,3},{4,5}则不是。


输入格式

第一行,一个整数N

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

输出格式

一个整数表示答案


样例

样例输入:

3

7 8 5 6 1 2 4 3

样例输出:

6


数据范围与提示

对于30%的数据,1≤N≤4; 对于全部的数据,1≤N≤12。


题解

这道题居然是搜索,简直难以置信,没办法,那就搜吧。

数据范围1≤N≤12,算一算发现是4096->5000,下意识${N}^{2}$。

首先,我们来考虑这样一个问题,如果我们执行的操作是3,1,2能完成排序,那么1,2,3也一定能,那么就是说,如果我们找到了一种操作数为x的方案,那么它对答案的贡献就是x!。

然后,再来考虑,因为每一种操作只能执行一次,所以这时候分以下四种情况:

  1.没有长度为2(i-1)的不符合顺序的序列对,那么直接尝试下一种操作。例:每一块的长度为4,序列为{1,3,2,4,5,6,7,8},{3,2}虽然不符合顺序,当前操作不能对它进行操作,那么我们执行下一个操作。

  2.存在一个这样的序列对,那么我们尝试进行内部交换。

  3.存在两个这样的序列对,例如:每一块的长度为2,序列为{1,2,7,8,5,6,3,4},那么我们需要枚举四种情况,分别是{1,2}与{5,6}换,{1,2}与{3,4}换,{7,8}与{5,6}换,{7,8}与{3,4}换。

  4.如果存在多于两个这样的序列对,那么这种方案一定行不通,赶快return就好了。

交换的时候暴力swap即可。

最后,大家可能还是毫无头绪,那么我再来解释一个问题。

我们在进行搜索的时候要从小往大搜索,因为这样,我们在交换两个长度更长的序列的时候已经保证了它里面是有序的,然后如果往后的操作可以将当前可以完成当前操作也可以完成的排序,那么就交给以后处理,例:当前每一块的为1,序列为{7,8,5,6,1,2,4,3},我们发现{7,8}和{5,6}在以后的操作中可以完成交换,那么我们现在就只尝试交换{4,3}。

统计答案时,将每一种方案的答案累加即可。


代码时刻

  1. #include<bits/stdc++.h>
  2. using namespace std;
  3. int n,sum,miao;
  4. int jc[13];
  5. int ans;
  6. int a[4097];
  7. void change(int x,int y,int w){do swap(a[x+w],a[y+w]);while(w--);}//暴力swap
  8. void dfs(int x,int w)
  9. {
  10. if(x==miao)//所有操作都已经尝试过了
  11. {
  12. ans+=jc[w];//记着加的是阶乘
  13. return;
  14. }
  15. int cnt=0;
  16. int flag[2]={0,0};//一定要是局部变量,100->25
  17. int wzc=1<<x;//记算长度
  18. for(int i=1;i<=n;i+=(wzc<<1))//统计位置,(wzc<<1)即为自动越过下一种操作可以处理掉的情况
  19. {
  20. if(a[i+wzc-1]+1!=a[i+wzc])
  21. {
  22. if(cnt==2)return;//如果两个以上就return
  23. flag[cnt++]=i;
  24. }
  25. }
  26. switch(cnt)
  27. {
  28. case 0://不存在
  29. {
  30. dfs(x+1,w);
  31. return;
  32. }
  33. case 1://存在一对
  34. {
  35. change(flag[0],flag[0]+wzc,wzc-1);
  36. dfs(x+1,w+1);
  37. change(flag[0],flag[0]+wzc,wzc-1);
  38. return;
  39. }
  40. case 2://存在两对,再分四种情况
  41. {
  42. if(a[flag[0]+wzc-1]+1==a[flag[1]+wzc]&&a[flag[0]+wzc]==a[flag[1]+wzc-1]+1)//先看看交换之后符不符合
  43. {
  44. change(flag[0],flag[1],wzc-1);
  45. dfs(x+1,w+1);
  46. change(flag[0],flag[1],wzc-1);
  47. change(flag[0]+wzc,flag[1]+wzc,wzc-1);
  48. dfs(x+1,w+1);
  49. change(flag[0]+wzc,flag[1]+wzc,wzc-1);
  50. }
  51. if(a[flag[0]+wzc]-1==a[flag[1]+wzc*2-1]&&a[flag[0]]==a[flag[1]+wzc-1]+1)
  52. {
  53. change(flag[0],flag[1]+wzc,wzc-1);
  54. dfs(x+1,w+1);
  55. change(flag[0],flag[1]+wzc,wzc-1);
  56. }
  57. if(a[flag[1]+wzc]-1==a[flag[0]+wzc*2-1]&&a[flag[1]]==a[flag[0]+wzc-1]+1)
  58. {
  59. change(flag[0]+wzc,flag[1],wzc-1);
  60. dfs(x+1,w+1);
  61. change(flag[0]+wzc,flag[1],wzc-1);
  62. }
  63. return;
  64. }
  65. }
  66. }
  67. int main()
  68. {
  69. scanf("%d",&n);
  70. miao=n;
  71. jc[0]=1;
  72. for(int i=1;i<=n;i++)
  73. jc[i]=jc[i-1]*i;//预处理阶乘
  74. n=1<<n;//现在n变为了序列长度了
  75. for(int i=1;i<=n;i++)
  76. scanf("%d",&a[i]);
  77. dfs(0,0);//开搜
  78. cout<<ans<<endl;
  79. return 0;
  80. }

rp++

[BZOJ3990]:[SDOI2015]排序(搜索)的更多相关文章

  1. [bzoj3990][SDOI2015]排序-搜索

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

  2. BZOJ 3990: [SDOI2015]排序 [搜索]

    3990: [SDOI2015]排序 题意:\(2^n\)的一个排列,给你n种操作,第i种把每\(2^{i-1}\)个数看成一段,交换任意两段.问是这个序列有序的操作方案数,两个操作序列不同,当且仅当 ...

  3. [BZOJ3990][SDOI2015]排序(DFS)

    3990: [SDOI2015]排序 Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 902  Solved: 463[Submit][Status][ ...

  4. BZOJ3990 [SDOI2015]排序 【搜索】

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

  5. Bzoj3990 [SDOI2015]排序

    Time Limit: 20 Sec  Memory Limit: 128 MBSubmit: 651  Solved: 338 Description 小A有一个1-2^N的排列A[1..2^N], ...

  6. BZOJ 3990 [SDOI2015]排序 ——搜索

    [题目分析] 可以发现,操作的先后顺序是不影响结果的,那么答案就是n!的和. 可以从小的步骤开始搜索,使得每一个当前最小的块都是上升的数列,然后看看是否可行即可. 复杂度好像是4^n [代码](哪里写 ...

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

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

  8. 006-筛选分类排序搜索查找Filter-Classificatio-Sort-Search-Find-Seek-Locate

    006-筛选分类排序搜索查找Filter-Classificatio-Sort-Search-Find-Seek-Locate https://www.cnblogs.com/delphixx/p/1 ...

  9. 【LG3322】[SDOI2015]排序

    [LG3322][SDOI2015]排序 题面 洛谷 题解 交换顺序显然不影响答案,所以每种本质不同的方案就给答案贡献次数的阶乘. 从小往大的交换每次至多\(4\)中决策,复杂度\(O(4^n)\). ...

随机推荐

  1. [转载]Linux软件包及dpkg\apt等方法

    Linux软件安装 来源:https://segmentfault.com/a/1190000011200004?share_user=1030000007255638 一.安装包分类 在Linux平 ...

  2. 七、for循环

    for循环

  3. css3之新增伪类

    css3新增了许多伪类,但是IE8以及更低版本的IE浏览器不支持css3伪类,所以在使用时要是涉及到布局等意象全局的样式,应该多考虑一下. 1.elem:nth-child(n) 这个伪类选中父元素下 ...

  4. 多层 iframe 嵌套 js 方法调用

    一下午一个这破问题,浪费了不少时间,怎么也实现不了我的上上级iframe 刷新.NND. 实现了,记录一下下吧: window.parent.parent.document.getElementByI ...

  5. 【vue】iView-admin2.0动态菜单路由【版2】

    依照iView-admin2.0动态菜单路由[版1] 归纳几个节点动态路由获取方式2 ——> easymock假数据 ——> 数据转组件处理.addRoutes ——> localS ...

  6. iperf测试流量转发(nginx反向代理tcp/udp)

    一.准备工作 服务器1:192.168.33.102     搭建nginx服务,作为反向代理的中转站 服务器2:192.168.33.103    nginx要反向代理的服务器 服务器3:192.1 ...

  7. js 判断确切判断Array和Object

    js的数组其实是特殊的对象. 这就导致: typeof [1,2,3] === 'object' [1,2,3] instanceof Object  和 [1,2,3] instanceof Arr ...

  8. logstash操作

    1.安装 1>安装java 2> #wget https://artifacts.elastic.co/downloads/logstash/logstash-5.6.3.tar.gz#t ...

  9. 清北学堂提高组突破营游记day6

    还有一天就结束了..QWQ 好快啊. 昨天没讲完的博弈论DP: 一个标准的博弈论dp,一般问的是是否先手赢. 博弈论最关键的问题:dp过程. 对于一个问题,一定有很多状态,每个状态可以转移到其他的一些 ...

  10. Spring 整合过滤器

    过滤器Filter是Servlet的一个技术,可通过过滤器对请求进行拦截,比如读取session判断用户是否登录.判断访问的请求URL是否有权限. 1.使用@WebFilter注解 controlle ...