[BZOJ3990]:[SDOI2015]排序(搜索)
题目传送门
题目描述
小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
输出格式
一个整数表示答案
样例
样例输入:
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]排序(搜索)的更多相关文章
- [bzoj3990][SDOI2015]排序-搜索
Brief Description 小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1<=i<= ...
- BZOJ 3990: [SDOI2015]排序 [搜索]
3990: [SDOI2015]排序 题意:\(2^n\)的一个排列,给你n种操作,第i种把每\(2^{i-1}\)个数看成一段,交换任意两段.问是这个序列有序的操作方案数,两个操作序列不同,当且仅当 ...
- [BZOJ3990][SDOI2015]排序(DFS)
3990: [SDOI2015]排序 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 902 Solved: 463[Submit][Status][ ...
- BZOJ3990 [SDOI2015]排序 【搜索】
题目 小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1<=i<=N),第i中操作为将序列从左到 ...
- Bzoj3990 [SDOI2015]排序
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 651 Solved: 338 Description 小A有一个1-2^N的排列A[1..2^N], ...
- BZOJ 3990 [SDOI2015]排序 ——搜索
[题目分析] 可以发现,操作的先后顺序是不影响结果的,那么答案就是n!的和. 可以从小的步骤开始搜索,使得每一个当前最小的块都是上升的数列,然后看看是否可行即可. 复杂度好像是4^n [代码](哪里写 ...
- BZOJ 3990: [SDOI2015]排序(搜索+剪枝)
[SDOI2015]排序 Description 小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1< ...
- 006-筛选分类排序搜索查找Filter-Classificatio-Sort-Search-Find-Seek-Locate
006-筛选分类排序搜索查找Filter-Classificatio-Sort-Search-Find-Seek-Locate https://www.cnblogs.com/delphixx/p/1 ...
- 【LG3322】[SDOI2015]排序
[LG3322][SDOI2015]排序 题面 洛谷 题解 交换顺序显然不影响答案,所以每种本质不同的方案就给答案贡献次数的阶乘. 从小往大的交换每次至多\(4\)中决策,复杂度\(O(4^n)\). ...
随机推荐
- 洛谷 P1072 Hankson 的趣味题 题解
题面 提前知识:gcd(a/d,b/d)*d=gcd(a,b); lcm(a,b)=a*b/gcd(a,b); 那么可以比较轻松的算出:gcd(x/a1,a0/a1)==gcd(b1/b0,b1/x) ...
- Codeforces 1209E2. Rotate Columns (hard version)
传送门 发现 $n$ 很小,考虑状压 $dp$,但是如果强行枚举列并枚举置换再转移复杂度太高了 考虑推推结论,发现我们只要保留列最大值最大的 $n$ 列即可,证明好像挺显然: 假设我们让列最大值比较小 ...
- 关于echarts 重绘/图表切换/数据清空
容器id 为main var myChart=document.getElementById("main") myChart.removeAttribute("_echa ...
- java 内部类复习
/** * 内部类详解 * * @author shao * */ public class InnerClass { public static void main(String[] args) { ...
- 微信小程序自定义字体及自定义图标问题说明
自定义图标及自定义字体,一直是很多小程序开发者的心病,其实本站是很多解决方案的,为了集中起来,方便直接跳过此坑,我特别做了这次针对字体及字体图标的跳坑: 相关文章:微信小程序添加并使用外部字体(成功添 ...
- 交叉工具链和makefile
交叉工具链: arm-linux-gcc:交叉编译器 arm-linux-ld:交叉连接器 arm-linux-readelf:交叉ELF文件工具 arm-linux-objdump:交叉反汇编器 a ...
- 我来说说XML文件中的xmlns、xmlns:xsi和xsi:schemaLocation、dtd文件的具体含义
文章摘自:https://yq.aliyun.com/articles/40353 http://www.cnblogs.com/zhao1949/p/5652167.ht ...
- JSONP 跨域请求原理
0x00 简介 由于浏览器的同源策略,我们想要从别的域获取数据变得困难,需要特殊的技术才能获取 0x01 使用 客户域:client.com 服务器(他域):server.com 如客户想访问 : h ...
- Linux 安装 nginx 安装PCRE库
PCRE(Perl Compatible Regular Expressions)是一个Perl库,包括 perl 兼容的正则表达式库.这些在执行正规表达式模式匹配时用与Perl 5同样的语法和语义是 ...
- vue interceptors(拦截器)
拦截器 顾名思义: 就是半路个您劫持, 拦截器 其实在项目和自己写demo中,总会遇到请求方面需要在请求头里面做判断或者添加一些东西, 这时候 vue 中应用中axios的 interceptors ...