[BZOJ3990][SDOI2015][LOJ#2181]-排序
说实话,这个题真好(?)
<BZOJ题面>
<LOJ题面>
看到这个题,一时没有思路
但是
我想到了一个错解:归并
这个题真的有一点把我们的思路往归并上引
于是WA10
诶?我归并写错了
以下是正解
DFS
我们会发现,这个题的
每一种操作,只能有一个
好办了
因为大的交换区间(我们暂且这么叫它)无法处理更小区间上的错位
而且,大的区间交换会改变小的交换的位置,这样如果我们找到一种可行方案(含$N$个操作)
这个方案解的全排列都可行,对答案的贡献就是$N!$
(有序:依次+1,如{1,2,3},其余情况无序)
所以DFS应从小往大进行,并且一边处理一边检测更小一段是否有序
处理完的区间必须有序,且每一次处理都不能超过一次
那么下面是处理的具体情况
发现在当前的区段,无序的有$k$个
$k=0$时,不需要交换(如果您非要交换那只能WA了)
$k=1$时,将无序区段整理有序
$k=2$时,将两段无序的区间进行整理,有四种情况,见下
$k \ge 3$时,当前操作无论如何也无法处理,返回
- 在此之下是过于仔细的讲解了,只看题解的可以停了~(下面约为源码)
将$k=2$时的情况讨论:
用几个式子举例
1.两个外侧交换
第一块的第一个子块与第二个的第一个子块相差$2^n$
7 8 3 4 5 6 1 2 可以交换
5 6 3 4 7 8 1 2 不行
2.两个内侧交换
第一块的第一个子块与第二个的第二个子块相差$2^n$
1 2 5 6 3 4 7 8 可以
1 2 7 8 3 4 5 6 不行
3.一内一外交换
第一块的第一个子块与第二个的第一个子块相差$2^n$
第4种情况归在这里面,同样的判断条件即
[1][3]交换[2][4]交换
1 2 5 6 3 4 7 8 可以
1 2 7 8 3 4 5 6 不行
总之记得把换过的判一下
源码:
其实以上判断用for循环都可以搞定,蒟蒻调出了if-else的正解
#include <iostream>
#include <cstring>
#include <cstdio> //#include "debug.h" #define LL long long
#define N (1<<12)+10 using namespace std; int arr[N],dat[N];
int pown[15],fac[15];
int n;
LL ans=0;
LL jc(int n){
LL j=1;
for(int i=2;i<=n;i++){
j*=i;
}
return j;
}
void sswap(int f1,int f2,int l){
//cout<<f1<<"<->"<<f2<<" len:"<<l<<endl;
for(int i=0;i<l;i++){
dat[f1+i]=arr[f1+i];
dat[f2+i]=arr[f2+i];
arr[f1+i]=dat[f2+i];
arr[f2+i]=dat[f1+i];
}
}
bool is_ok(){
for(int i=1;i<=pown[n];i++)
if(arr[i]!=i)return 0;
return 1;
}
void dfs(int k,int cn){//2^k
//cout<<"DFS"<<k<<"change number:"<<cn<<endl;
//debug<<"Now the array has been:"<<endl;
//pour(arr,1,pown[n],3,"Array");
if(is_ok()){
if(cn!=0)ans+=fac[cn];
return;
}
if(k>n)return ;
int ln=0;
for(int i=1;i<=pown[n];i+=pown[k]){
if(arr[i+pown[k-1]]!=arr[i]+pown[k-1]){
ln++;//cout<<"Find a Unordered part "<<i<<" Total: "<<ln<<endl;
}
}
if(ln==0){
dfs(k+1,cn);
}
else if(ln==1){
for(int i=1;i<=pown[n];i+=pown[k]){
if(arr[i+pown[k-1]]!=arr[i]+pown[k-1]){
sswap(i,i+pown[k-1],pown[k-1]);
dfs(k+1,cn+1);
sswap(i,i+pown[k-1],pown[k-1]);
break;
}
}
}
else if(ln==2){
int wz[2];
for(int i=1,j=0;i<=pown[n];i+=pown[k]){
if(arr[i+pown[k-1]]!=arr[i]+pown[k-1]){
wz[j]=i;
j++;
if(j==2)break;
}
}
//debug<<"wz1 "<<wz[0]<<" wz2 "<<wz[1]<<" pown" <<pown[k-1]<<endl;
//debug<<"init:"<<arr[wz[0]]<<" "<<arr[wz[1]]<<NL;
if(arr[wz[0]]+pown[k-1] == arr[wz[1]]){//换中间的
if(arr[wz[0]+pown[k-1]]+pown[k-1] != arr[wz[1]+pown[k-1]])//换后的后面
return;
sswap(wz[0]+pown[k-1],wz[1],pown[k-1]);
dfs(k+1,cn+1);
sswap(wz[0]+pown[k-1],wz[1],pown[k-1]);
}
else if(arr[wz[1]+pown[k-1]] + pown[k-1] == arr[wz[0]+pown[k-1]]){//换两边的
if(arr[wz[1]]+pown[k-1] != arr[wz[0]])//换后的后面
return ;
sswap(wz[0],wz[1]+pown[k-1],pown[k-1]);
dfs(k+1,cn+1);
sswap(wz[0],wz[1]+pown[k-1],pown[k-1]);
}
else if(arr[wz[0]]+pown[k-1] == arr[wz[1]+pown[k-1]]){
if(arr[wz[0]+pown[k-1]] != arr[wz[1]]+pown[k-1])//换后如果不成立
return;
sswap(wz[0]+pown[k-1],wz[1]+pown[k-1],pown[k-1]);//换后面的两个
dfs(k+1,cn+1);
sswap(wz[0]+pown[k-1],wz[1]+pown[k-1],pown[k-1]);
sswap(wz[0],wz[1],pown[k-1]);//换前面的两个
dfs(k+1,cn+1);
sswap(wz[0],wz[1],pown[k-1]);
}
else return ;
}
else return;
}
int prerun(){
pown[0]=1;fac[0]=1;
for(int i=1;i<=14;i++){
pown[i]=pown[i-1]*2;
fac[i]=fac[i-1]*i;
}
//pour(pown,1,14,5,"Pow");
//pour(fac ,1,14,5,"fac");
}
int main(){
prerun();
scanf("%d",&n);
for(int i=1;i<=pown[n];i++)
scanf("%d",&arr[i]);
dfs(1,0);
cout<<ans<<endl;
}
[BZOJ3990][SDOI2015][LOJ#2181]-排序的更多相关文章
- [BZOJ3990][SDOI2015]排序(DFS)
3990: [SDOI2015]排序 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 902 Solved: 463[Submit][Status][ ...
- Bzoj3990 [SDOI2015]排序
Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 651 Solved: 338 Description 小A有一个1-2^N的排列A[1..2^N], ...
- [bzoj3990][SDOI2015]排序-搜索
Brief Description 小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1<=i<= ...
- BZOJ3990 [SDOI2015]排序 【搜索】
题目 小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1<=i<=N),第i中操作为将序列从左到 ...
- [BZOJ3990]:[SDOI2015]排序(搜索)
题目传送门 题目描述 小A有一个1-${2}^{N}$的排列A[1..${2}^{N}$],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1≤i≤N), ...
- [暑假的bzoj刷水记录]
(这篇我就不信有网站来扣) 这个暑假打算刷刷题啥的 但是写博客好累啊 堆一起算了 隔一段更新一下. 7月27号之前刷的的就不写了 , 写的累 代码不贴了,可以找我要啊.. 2017.8.27upd ...
- AHOI2018训练日程(3.10~4.12)
(总计:共90题) 3.10~3.16:17题 3.17~3.23:6题 3.24~3.30:17题 3.31~4.6:21题 4.7~4.12:29题 ZJOI&&FJOI(6题) ...
- 【LOJ】#2181. 「SDOI2015」排序
题解 还以为是啥毒瘤题 然后是个搜索题 复杂度算起来挺大 然后跑起来就连0.1ms不到= = 就是从大到小进行每种操作,搜出来一种操作就乘上一个操作数的阶乘就行 如果现在进行的操作操作\(2^i\)那 ...
- BZOJ3990:[SDOI2015]排序——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=3990 小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作 ...
随机推荐
- Vagrant box ubuntu/xenial64 添加vagrant用户解决没有登录密码的问题
参考了Vagrant box ubuntu/xenial64 の ubuntuユーザ の passwordについて 1. 可以通过 Git Bash 使用 vagrant ssh 登录到Ubuntu ...
- 进程互斥软件实现之Lamport面包店算法
一. 进程互斥的实现方式 1. 软件方式: 保护临界区, 自己编写代码来实现对进程的控制. Dekker算法Peterson算法Lamport算法等 2. 硬件方式: 使用特殊指令保护临界区. 开关中 ...
- Ubuntu 18.04 Linux上安装Etherpad,基于Web的实时协作编辑器
介绍 Etherpad是一个开源的,基于Web的实时协作编辑器(http://www.0834nanke.com) 它允许多个人使用他们的Web浏览器同时编辑文档. 它还提供了一些很酷的功能,如富文本 ...
- JWT生成token
1.JWT简介 JSON Web Token 简称JWT.一个JWT实际上就是一个字符串,它由三部分组成,头部.载荷与签名.JWT生成的token是这样的 2.Json Web Token(JWT)生 ...
- springboot让内置tomcat失效
一.POM(去除内嵌tomcat后,需要添加servlet依赖) <dependency> <groupId>org.springframework.boot</grou ...
- php链表笔记:单链表反转
<?php /** * Created by PhpStorm. * User: huizhou * Date: 2018/12/1 * Time: 11:41 */ /** * 1.链表的反转 ...
- 修改数组中对象的key值
遇见场景:echart图表中后台返回我的数据,后台无法修改key值,但是echart渲染图表的时候,需要用 var m2R2Data= [ {value:335,name:"种类01 335 ...
- JS 根据今天的日期获取本周星期一与星期天的日期
var now = new Date(); var nowTime = now.getTime() ; var day = now.getDay(); var oneDayTime = 24*60*6 ...
- Python网络爬虫之三种数据解析方式 (xpath, 正则, bs4)
引入 回顾requests实现数据爬取的流程 指定url 基于requests模块发起请求 获取响应对象中的数据 进行持久化存储 其实,在上述流程中还需要较为重要的一步,就是在持久化存储之前需要进行指 ...
- 用docker部署zabbix
官方文档 https://www.zabbix.com/documentation/3.4/zh/manual/installation/containers 1 启动一个空的Mysql服务器实例 d ...