说实话,这个题真好(?)

<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]-排序的更多相关文章

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

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

  2. Bzoj3990 [SDOI2015]排序

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

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

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

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

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

  5. [BZOJ3990]:[SDOI2015]排序(搜索)

    题目传送门 题目描述 小A有一个1-${2}^{N}$的排列A[1..${2}^{N}$],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1≤i≤N), ...

  6. [暑假的bzoj刷水记录]

    (这篇我就不信有网站来扣) 这个暑假打算刷刷题啥的 但是写博客好累啊  堆一起算了 隔一段更新一下.  7月27号之前刷的的就不写了 , 写的累 代码不贴了,可以找我要啊.. 2017.8.27upd ...

  7. 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题) ...

  8. 【LOJ】#2181. 「SDOI2015」排序

    题解 还以为是啥毒瘤题 然后是个搜索题 复杂度算起来挺大 然后跑起来就连0.1ms不到= = 就是从大到小进行每种操作,搜出来一种操作就乘上一个操作数的阶乘就行 如果现在进行的操作操作\(2^i\)那 ...

  9. BZOJ3990:[SDOI2015]排序——题解

    https://www.lydsy.com/JudgeOnline/problem.php?id=3990 小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作 ...

随机推荐

  1. SQLServer 2008 还原数据库备份版本不兼容的问题

    我们准备还原一个数据库备份的时候,经常会弹出这样的错误:System.Data.SqlClient.SqlError: 该数据库是在运行版本 10.50.1600 的服务器上备份的.该版本与此服务器( ...

  2. nodejs实现读取文件

    今天后端同事下班,想让我读取一个文件的内容.我想这个是小忙啊,就立马答应了. 我知道这个是nodejs读取,可是我又想,平时我们都要起一个服务才能够运行node服务器, 比如如下代码 var http ...

  3. 异常处理记录: Servlet class X is not a javax.servlet.Servlet

    使用Maven的tomcat插件启动Web项目, 访问资源时, 发生如下异常: https://stackoverflow.com/questions/1036702/my-class-is-not- ...

  4. 关于str的打印格式

    实际上一般的打印格式应该是这样的: %[(keyname)][flags][width][.precision]typecode (1) keyname: 用于打印Dict类型时做索引; (2) fl ...

  5. [JZOJ3187]【GDOI2013模拟8】的士

    题目 描述 题目大意 在一个数轴上,有些人要从某个点到达另一个点. 出租车从最左端出发,将所有人送到它们的目的地,最终到达最右边的点. 出租车只能做一个乘客,并且可以在图中将乘客丢下. 问最短时间. ...

  6. Spring MVC(八)--控制器接受简单列表参数

    有些场景下需要向后台传递一个数组,比如批量删除传多个ID的情况,可以使用数组传递,数组中的ID元素为简单类型,即基本类型. 现在我的测试场景是:要从数据库中查询minId<id<maxId ...

  7. SpringBoot 02_返回json数据

    在SpringBoot 01_HelloWorld的基础上来返回json的数据,现在前后端分离的情况下多数都是通过Json来进行交互,下面就来利用SpringBoot返回Json格式的数据. 1:新建 ...

  8. css3之文本text-overflow 与 word-wrap, word-break

    CSS3 Text Overflow属性 CSS3文本溢出属性指定应向用户如何显示溢出内容 语法: text-overflow:clip | ellipsis 但是text-overflow只是用来说 ...

  9. Kubernetes架构介绍

    目录 Kubernetes架构 k8s架构图 一.K8S Master节点 API Server Scheduler Controller Manager ETCD 二.K8S Node节点 Kube ...

  10. node概览和安装

    一.node是一个平台环境,可以运行js代码的服务器端平台. 设计最初node是用来解决并发问题的,现在可以用来放在服务端使用. node平台的有优点:运行速度快,支持高并发,轻便.小巧 但是与jav ...