题面

传送门

思路

首先,这道题目有一个非常显然(但是我不会严格证明,只能意会一下)的结论:一个合法的操作序列中,任意两个操作是可以互换的

那么,这个结论加上本题极小的数据范围,为什么不搜索一下呢?

ok说干就干

既然顺序不重要,我们就从交换两个长度为1的序列开始搜索

这时,就有另外一个性质:因为我们每种交换能且只能做一次,所以有的情况下我们是一定无法完成的

考虑交换两个长度为$2k$的序列,这时我们把整个序列分成长度为$2{k+1}$的段

如果这些段全部都是连续且递增(也就是3,4,5,6这样)的,说明这个操作不用做

如果这些段里面有一个不是连续递增的,就把这个段的前后两半交换

如果这些段里面有两个不是连续递增的,那么我们对于这两段的两半,讨论四种交换的情况,分别判断它们是否合法

如果这些段里面有超过两个不是连续递增的,那么可以证明此时我们一定无法完成排序,可以把这个搜索枝剪掉

这样操作以后,我们会发现,对于所有合法的长度为$2k$的序列的交换,完成之后的序列,一定由若干个长度为$2{k+1}$的连续递增序列构成

这时我们再递归到下一层处理,递归n层以后要判断一下最终序列是否是1-n,然后用当前这个操作序列中的操作个数的阶乘加到答案上(因为可以随意改变操作顺序)

总时间复杂度为$O(2^{24})$,但是远远达不到这个值

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define ll long long
#include<vector>
using namespace std;
inline ll read(){
ll re=0,flag=1;char ch=getchar();
while(ch>'9'||ch<'0'){
if(ch=='-') flag=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
return re*flag;
}
ll n,a[5010],tmp[5010][15];
vector<int>ans;//不同的操作序列的操作个数
void dfs(ll k,ll num){
ll i,j,t,cnt=0,m1,m2;//cnt是非连续递增的段的个数,m1m2是前两个的起点
if(k==n+1){
for(i=1;i<=(1<<n);i++) if(tmp[i][k]!=i) return;
ans.push_back(num);return;//注意到
}
for(i=1;i<=(1<<n);i+=(1<<k)){//统计cnt
t=tmp[i][k];
for(j=i+1;j<i+(1<<k);j++){
if(tmp[j][k]!=t+j-i){
if(cnt==2) return;
cnt++;
if(cnt==1) m1=i;
else m2=i;
break;
}
}
}
if(cnt>2) return;
for(i=1;i<=(1<<n);i++) tmp[i][k+1]=tmp[i][k];
if(cnt==0){
dfs(k+1,num);return;
}
if(cnt==1){
for(j=m1;j<m1+(1<<k-1);j++) swap(tmp[j][k+1],tmp[j+(1<<k-1)][k+1]);
dfs(k+1,num+1);return;
}
bool flag=1;//这里开始枚举四种情况
for(i=1;i<=(1<<k-1);i++) swap(tmp[m1+i-1][k+1],tmp[m2+i-1][k+1]);
for(i=1;i<=(1<<k);i++) if(tmp[m1+i-1][k+1]-tmp[m1][k+1]!=i-1) flag=0;
for(i=1;i<=(1<<k);i++) if(tmp[m2+i-1][k+1]-tmp[m2][k+1]!=i-1) flag=0;
if(flag) dfs(k+1,num+1);
flag=1;
for(i=1;i<=(1<<n);i++) tmp[i][k+1]=tmp[i][k];
for(i=1;i<=(1<<k-1);i++) swap(tmp[m1+(1<<k-1)+i-1][k+1],tmp[m2+i-1][k+1]);
for(i=1;i<=(1<<k);i++) if(tmp[m1+i-1][k+1]-tmp[m1][k+1]!=i-1) flag=0;
for(i=1;i<=(1<<k);i++) if(tmp[m2+i-1][k+1]-tmp[m2][k+1]!=i-1) flag=0;
if(flag) dfs(k+1,num+1);
flag=1;
for(i=1;i<=(1<<n);i++) tmp[i][k+1]=tmp[i][k];
for(i=1;i<=(1<<k-1);i++) swap(tmp[m1+i-1][k+1],tmp[m2+(1<<k-1)+i-1][k+1]);
for(i=1;i<=(1<<k);i++) if(tmp[m1+i-1][k+1]-tmp[m1][k+1]!=i-1) flag=0;
for(i=1;i<=(1<<k);i++) if(tmp[m2+i-1][k+1]-tmp[m2][k+1]!=i-1) flag=0;
if(flag) dfs(k+1,num+1);
flag=1;
for(i=1;i<=(1<<n);i++) tmp[i][k+1]=tmp[i][k];
for(i=1;i<=(1<<k-1);i++) swap(tmp[m1+(1<<k-1)+i-1][k+1],tmp[m2+(1<<k-1)+i-1][k+1]);
for(i=1;i<=(1<<k);i++) if(tmp[m1+i-1][k+1]-tmp[m1][k+1]!=i-1) flag=0;
for(i=1;i<=(1<<k);i++) if(tmp[m2+i-1][k+1]-tmp[m2][k+1]!=i-1) flag=0;
if(flag) dfs(k+1,num+1);
}
int main(){
n=read();ll i,tans=1,out=0,j;
for(i=1;i<=(1<<n);i++) a[i]=read(),tmp[i][1]=a[i];
dfs(1,0);
for(i=0;i<ans.size();i++){//阶乘更新答案
tans=1;
for(j=1;j<=ans[i];j++) tans*=j;
out+=tans;
}
cout<<out;
}

[SDOI2015][bzoj3990] 序列 [搜索]的更多相关文章

  1. 【SDOI2015】序列统计 解题报告

    2119: [BZOJ3992][SDOI2015]序列统计 Description 小\(C\)有一个集合\(S\),里面的元素都是小于\(M\)的非负整数. 他用程序编写了一个数列生成器,可以生成 ...

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

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

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

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

  4. bzoj3992【SDOI2015】序列统计

    3992: [SDOI2015]序列统计 Time Limit: 30 Sec  Memory Limit: 128 MB Submit: 673  Solved: 327 [Submit][Stat ...

  5. BZOJ 3990: [SDOI2015]排序(搜索+剪枝)

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

  6. [sdoi2015]排序(搜索+剪枝优化)

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

  7. [SDOI2015]排序 题解 (搜索)

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

  8. 基于visual Studio2013解决面试题之0309左移递减序列搜索

     题目

  9. BZOJ 3992 【SDOI2015】 序列统计

    题目链接:序列统计 我来复习板子了……这道题也是我写的第一发求原根啊? 求原根方法: 从小到大依次枚举原根.设当前枚举的原根为\(x\),模数为\(p\),\(p-1\)的质因数分别为\(p_1,p_ ...

随机推荐

  1. ref是什么?

    ref是组件的特殊属性,组件被渲染后,指向组件的一个引用.可以通过组件的ref属性,来获取真实的组件. 因为,组件并不是真正的DOM节点,而是存在于内存中的一种数据结构,称为虚拟的DOM,只有当它真正 ...

  2. 【主席树上二分】bzoj5361: [Lydsy1805月赛]对称数

    随机化选讲例题 题目大意 小 Q 认为,偶数具有对称美,而奇数则没有.给定一棵 n 个点的树,任意两点之间有且仅有一条直接或间接路径.这些点编号依次为 1 到 n,其中编号为 i 的点上有一个正整数 ...

  3. 【赛时总结】◇赛时·V◇ Codeforces Round #486 Div3

    ◇赛时·V◇ Codeforces Round #486 Div3 又是一场历史悠久的比赛,老师拉着我回来考古了……为了不抢了后面一些同学的排名,我没有做A题 ◆ 题目&解析 [B题]Subs ...

  4. selenium学习总结

    selenium主要用来做web自动化,分1.0和2.0两个版本,1.0包括selenium IDE.selenium Grid.selenium Remote Control,2.0在1.0的基础上 ...

  5. 一个优秀的SSH远程终端工具

    SSH远程终端工具是一款在Windows界面下用来访问远端不同系统下的服务器,从而比较好的达到远程控制终端的目的.向我们操控集群的时候,如果每台机器都安装一个显示器和键盘也是一个不小的花费,而远程终端 ...

  6. JAVA / MySql 编程——第五章 事务、视图、索引、备份和恢复

    1.事务(Transaction): 事务是将一系列数据操作绑成一个整体进行统一管理. 如果一事务执行成功,则咋子该事务中进行的所有数据更改均会提交,称为数据库中的永久成部分. 如果事务执行是遇到错误 ...

  7. fastadmin 后台管理框架使用技巧(持续更新中)

    fastadmin 后台管理框架使用技巧(持续更新中) FastAdmin是一款基于ThinkPHP5+Bootstrap的极速后台开发框架,具体介绍,请查看文档,文档地址为:https://doc. ...

  8. C++基础 new和delete

    1.new delete 的使用 (1)基本数据类型 ); delete p; int *p = (int *)malloc(sizeof(int)); *p = ;free(p); (2)数组 ]; ...

  9. spider_main.py

    coding=UTF-8 import html_download import html_outputer import html_parser import url_maneger class S ...

  10. python-openpyxl操作excel

    python 读写 excel有很多选择,但是,方便操作的库不多,在我尝试了几个库之后,我觉得两个比较方便的库是xlrd/xlwt.openpyxl. 之所以推荐这两个库是因为这两个库分别操作的是不同 ...