[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可以执行的操作 ...
随机推荐
- struts2文件上传,文件类型 allowedTypes对应
'.a' : 'application/octet-stream', 2 '.ai' : 'application/postscript', 3 '.aif' : 'audio/x-aiff', 4 ...
- Qt分割线
方法:使用QFrame QFrame * line = new QFrame(); line->setFrameShape(QFrame::HLine); line->setFrameSh ...
- Spring Cloud Alibaba发布第二个版本,Spring 发来贺电
还是熟悉的面孔,还是熟悉的味道,不同的是,这次的配方升级了. 今年10月底,Spring Cloud联合创始人Spencer Gibb在Spring官网的博客页面宣布:阿里巴巴开源 Spring Cl ...
- 自己整理的一个访问SQLite3数据库的C++类
原文地址:自己整理的一个访问SQLite3数据库的C++类作者:vigra 近日,对SQLite3的使用进行了研究.真不愧是优秀的嵌入数据库,API接口也极其简捷.基本上只要使用以下几个接口就能完成数 ...
- 使用DUILIB建立项目
使用DUILIB加载XML界面 这篇主要目的就是教给大家怎样在自己的工程中加载XML界面,这是最基本的应用,对于界面控件响应啥的,我就不讲了,在大家懂了这个之后,我会给大家一个其它人写的博客,再看他的 ...
- LUOGU P3355 骑士共存问题(二分图最大独立集)
传送门 因为骑士只能走"日"字,所以一定是从一个奇点到偶点或偶点到奇点,那么这就是一张二分图,题目要求的其实就是二分图的最大独立集.最大独立集=n-最大匹配. #include&l ...
- springboot+mybatis+达梦数据库
准备工作: 首先,安装达梦6数据库.安装完之后如下建表 然后,很重要的一点(写法一定要这样写,否则无限报错) 达梦数据库查表方式: select * from "库名". ...
- c语言学习笔记 - 文件操作
#include <stdio.h>#include <time.h> int main(void){ time_t t; //类似于size_t那 ...
- day 48 jQuery快速入门
jQuery快速入门 jQuery jQuery介绍 1.jQuery是一个轻量级的.兼容多浏览器的JavaScript库. 2.jQuery使用户能够更方便地处理HTML Document.Ev ...
- 关于MQ 消息队列的通俗理解和 rabbitMQ 使用
消息队列,一听很高大上,现在很多分布式系统都在用这个消息中间件 网上一搜, 说的都是些原理. 说下我的通俗理解, 你网上买了, 快递员给你投递, 会出现什么问题呢? 1 你不定时在家, 快递员 来了 ...