[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可以执行的操作 ...
随机推荐
- 【笔记篇】C#笔记2
返回目录:目录请戳这里~ C#数组 基本概念不提.. int[] a; bool[] b = new bool[10]; float[] c = {0.5, 57.0, 233.3, 12345.67 ...
- Luogu P1041 传染病控制(搜索)
P1041 传染病控制 题意 题目背景 近来,一种新的传染病肆虐全球.蓬莱国也发现了零星感染者,为防止该病在蓬莱国大范围流行,该国政府决定不惜一切代价控制传染病的蔓延.不幸的是,由于人们尚未完全认识这 ...
- 威胁预警|首现新型RDPMiner挖矿蠕虫 受害主机易被添加恶意账户
近日,阿里云安全发现一种新型挖矿蠕虫RDPMiner,通过爆破Windows Server 3389端口RDP服务的方式进行挖矿木马传播,致使用户CPU占用率暴涨,机器卡顿,更被创建名为Default ...
- 重磅榜单!互联网金融Top100总估值超1.1万亿,27家独角兽上榜!
时隔4个月,爱分析的“中国互联网金融企业估值排行榜”更新了! 在这4个月当中,我们调研了数十位企业创始人.专业投资人以及资深行业专家,尤其针对金服集团.消费金融.财富管理.征信等领域进行了深入研究.因 ...
- 菜鸟nginx源码剖析数据结构篇(十一) 共享内存ngx_shm_t[转]
菜鸟nginx源码剖析数据结构篇(十一) 共享内存ngx_shm_t Author:Echo Chen(陈斌) Email:chenb19870707@gmail.com Blog:Blog.csdn ...
- Matlab系列作业
(2019年2月19日注:Matlab这门课是在我大四上学期经历的,那时候开这篇文章是为了记录学习Matlab的时候遇到的坑,所以将所有的作业题合并到一篇文章中) 1.创建一个10*10的矩阵,矩阵所 ...
- sip会话流程以及sip介绍(1)
参考连接 :https://www.2cto.com/kf/201609/546336.html https://www.w3cschool.cn/session_initiation_protoco ...
- 安装office2019
win10系统安装office2019 安装文件下载 https://pan.baidu.com/s/1VnqJ-hNwysPKBhdzE3FSww#list/path=%2F&parentP ...
- centos Python2.6 升级到2.7
需求: centos 6.x 系统默认Python 版本都是2.6,实际生产环境中需要用到Python 2.7.x Python 2.7 下载地址 [root@ansible package]# wg ...
- P1080(python 高精度)
https://www.luogu.org/problem/P1080 n=int(input()) s=input().split() S=int(s[0]) T=int(s[1]) a=[] fo ...