题目传送门


题目描述

小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}。

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


代码时刻

#include<bits/stdc++.h>
using namespace std;
int n,sum,miao;
int jc[13];
int ans;
int a[4097];
void change(int x,int y,int w){do swap(a[x+w],a[y+w]);while(w--);}//暴力swap
void dfs(int x,int w)
{
if(x==miao)//所有操作都已经尝试过了
{
ans+=jc[w];//记着加的是阶乘
return;
}
int cnt=0;
int flag[2]={0,0};//一定要是局部变量,100->25
int wzc=1<<x;//记算长度
for(int i=1;i<=n;i+=(wzc<<1))//统计位置,(wzc<<1)即为自动越过下一种操作可以处理掉的情况
{
if(a[i+wzc-1]+1!=a[i+wzc])
{
if(cnt==2)return;//如果两个以上就return
flag[cnt++]=i;
}
}
switch(cnt)
{
case 0://不存在
{
dfs(x+1,w);
return;
}
case 1://存在一对
{
change(flag[0],flag[0]+wzc,wzc-1);
dfs(x+1,w+1);
change(flag[0],flag[0]+wzc,wzc-1);
return;
}
case 2://存在两对,再分四种情况
{
if(a[flag[0]+wzc-1]+1==a[flag[1]+wzc]&&a[flag[0]+wzc]==a[flag[1]+wzc-1]+1)//先看看交换之后符不符合
{
change(flag[0],flag[1],wzc-1);
dfs(x+1,w+1);
change(flag[0],flag[1],wzc-1);
change(flag[0]+wzc,flag[1]+wzc,wzc-1);
dfs(x+1,w+1);
change(flag[0]+wzc,flag[1]+wzc,wzc-1);
}
if(a[flag[0]+wzc]-1==a[flag[1]+wzc*2-1]&&a[flag[0]]==a[flag[1]+wzc-1]+1)
{
change(flag[0],flag[1]+wzc,wzc-1);
dfs(x+1,w+1);
change(flag[0],flag[1]+wzc,wzc-1);
}
if(a[flag[1]+wzc]-1==a[flag[0]+wzc*2-1]&&a[flag[1]]==a[flag[0]+wzc-1]+1)
{
change(flag[0]+wzc,flag[1],wzc-1);
dfs(x+1,w+1);
change(flag[0]+wzc,flag[1],wzc-1);
}
return;
}
}
}
int main()
{
scanf("%d",&n);
miao=n;
jc[0]=1;
for(int i=1;i<=n;i++)
jc[i]=jc[i-1]*i;//预处理阶乘
n=1<<n;//现在n变为了序列长度了
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
dfs(0,0);//开搜
cout<<ans<<endl;
return 0;
}

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. <<C++ Primer>> 第三章 字符串, 向量和数组 术语表

    术语表 第 3 章 字符串, 向量和数组 begin: 是 string 和 vector 的成员,返回指向第一个元素的迭代器.也是一个标准库函数,输入一个数字,返回指向该数字首元素的指针.    缓 ...

  2. [Vue] vuex-interview

    1.你有使用过 vuex 的 module 吗?主要是在什么场景下使用? 把状态全部集中在状态树上,非常难以维护. 按模块分成多个 module,状态树延伸多个分支,模块的状态内聚,主枝干放全局共享状 ...

  3. ivew组件上传图片文件的功能:

    解决的问题: 1.使用view的<Upload>组件实现图片文件的上传. 2.<Upload>组件action请求地址无法到自己写的后台. 3.前台base64的图片展示. 4 ...

  4. MySQL基础入门之常用命令介绍

    mysql命令介绍 mysql 是数据库管理命令 通过mysql --help来查看相关参数及使用说明 mysql --help                #mysql数据库管理命令 Usage: ...

  5. HTTP常用状态码详解

    HTTP状态码: HTTP定义遵循一条规则:所有状态码的第一个数字代表了响应的状态.1表示消息:2表示成功:3表示重定向:4表示请求错误:5.6表示服务器错误.如下图: 1xx: 这一类型的状态码,代 ...

  6. php强大的filter过滤用户输入

    <?php $filters = array //定义过滤的数组 ( "name" => array ( "filter"=>FILTER_S ...

  7. 树莓派3b+下一些常用的命令(Debian下)

    安装Mysqlsudo apt-get install mysql-server即可 注:第一次登陆是可能出现以下错误,则按顺序输入命令即可: ERROR 1698 (28000):Access de ...

  8. 一个显示 OpenCV Mat 图像的自定义 Qt 控件

    今天学习 Qt 的时候顺手写了一个,包含一个头文件 qcvdisplay.h 和一个源文件 qcvdisplay.cpp,因为这是 qt 默认的文件命名方式,在 Qt Designer 中提升控件时会 ...

  9. puppet之资源

    资源 资源的定义 一个帐号,一个文件,目录,软件包都可以称作是资源,每个资源的定义都具有标题,类型,以及一些列属性. 常见的资源有notify(调试与输出),file(配置文件),package(软件 ...

  10. python_实现员工信息表

    实现员工信息表 文件存储格式如下:id,name,age,phone,job1,Alex,22,13651054608,IT2,Egon,23,13304320533,Tearcher3,nezha, ...