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

<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. DbUtils要点小结

    一. DbUtils核心API 1. QueryRunner update方法 query方法 2. 各种Handler都实现ResultSetHandler接口 beanhandler beanli ...

  2. day1-字符串、列表

    字符串操作: name = "Wills Qian" # 创建字符串变量 print(len(name)) # 打印字符串长度 print(name[0]) # 提取第一个字符W ...

  3. eval()方法与str()方法

    eval()方法与str()方法 #_author:Administrator#date:2019/10/31 a={ 'q':{'xxx':3456}}#将一个字典转换成一个字符串a=str(a)p ...

  4. 动态设置背景图片,class,style

    1.动态设置背景图片<div v-if='img ' :style="{background: 'url('+ img +')',backgroundSize:cover }" ...

  5. 淼一淼A+B problem

    鲁迅:这可是道难题呢! 鲁迅:我没说过这话,不过确实在理. 某改题毕,但见LOJ之上有数「A+B」之AC记录.余亦尝闻A+B之趣味无穷,遂兴起而码之. 少顷,AC之,吾心所畅. #include< ...

  6. LUOGU P4777 【模板】扩展中国剩余定理(EXCRT)

    传送门 解题思路 扩展 $crt​$,就是中国剩余定理在模数不互质的情况下,首先对于方程 ​     $\begin{cases} x\equiv a_1\mod m_1\\x\equiv a_2\m ...

  7. Zuul的过滤器

    过滤器类型与请求生命周期:         Zuul中定义了4种标准过滤器类型,这些过滤器类型对应于请求的典型生命周期         PRE: 这种过滤器在请求被路由之前调用.可利用这种过滤器实现身 ...

  8. 服务器迁移部署PosEdi

    绑定 基本配置 高级配置

  9. css3中 百分比宽度减去固定宽度的写法

    div{ /*实现了宽度为父容器宽度减去固定的300像素*/ width:-webkit-calc(100% - 300px); width:-moz-calc(100% - 300px); widt ...

  10. linux socket error code

    errno.00 is: Successerrno.01 is: Operation not permittederrno.02 is: No such file or directoryerrno. ...