[sdoi2015]排序(搜索+剪枝优化)
Description
小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1<=i<=N),第i中操作为将序列从左到右划分为2^{N-i+1}段,每段恰好包括2^{i-1}个数,然后整体交换其中两段.小A想知道可以将数组A从小到大排序的不同的操作序列有多少个,小A认为两个操作序列不同,当且仅当操作个数不同,或者至少一个操作不同(种类不同或者操作位置不同).
Input
第一行,一个整数N
Output
一个整数表示答案
Sample Input
7 8 5 6 1 2 4 3
Sample Output
HINT
100%的数据, 1<=N<=12.
题解:
......搜索送命题
对于菜得不能再菜的垃圾博主,搜索真是这世界上最难的算法(dalao勿喷)。
考试时看到这题,觉得是道数学题或者是一道数据结构加数学题,结果看题解发现是一道搜索。
不会写搜索的垃圾博主当场吓尿。
但考试时输出阶乘qj测试点得了15pts,运气不错
咳咳...言归正传
其实首先要想到一个性质就是对于一个操作序列的顺序是不影响他的合法性的,也就是说每次多加一种操作对答案的贡献是阶乘的这也就是我没爆零的原因。
那么我们就只需要确定每个操作是不是要选就可以了。
我们从小到大dfs,dfs(now,x)表示选了now种方法,现在判断第x种方法。
显然递归入口dfs(0,1)。
然后我们考虑怎样剪枝。
实际上交换的过程就是把不合法的子序列进行交换得到合法的子序列。
然后我们就可以每次扫一遍,找出对于每次操作x,不合法的序列个数及不合法序列的开始位置以便交换。
如果有两个以上不合法的子序列那就完戏了,直接return。
如果没有不合法的子序列,那么就不需要进行这种操作,直接搜下一层。
如果有一个这种子序列,那么交换他的前一半和后一半,再判断是否合法,再进行搜索。
如果有两个这种子序列,那么判断四种情况,在进行搜索。
很多神犇只说四种情况,并没有说明白是哪四种情况,坑害了我这种懵逼的蒟蒻
其实也很好想就是判断前一段的前一段和后一段的前一段交换,前一段的后一段和后一段的前一段,前一段的前一段和后一段的后一段,前一段的后一段和后一段的前一段。
就似这四种情况辣。
另外还有要注意的是就是在写交换和判断两个过程时一定要处理好循环的边界问题,博主就因为这个被卡了好长时间。
(附上本人丑陋的代码)、
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<algorithm>
using namespace std;
int fac[],power[];int n;int num;
int a[<<|];
int res=;
int qpower(int a,int b){
int ans=;
while(b){
if(b&) ans=ans*a;
b>>=;
a=a*a;
}
return ans;
}
int check(int x,int k){
for(int i=;i<power[k];i++){//不要右边界
if(a[x+i]!=a[x+i-]+){
return ;
}
}
return ;
}
void swap(int x,int y,int k){
for(int i=;i<power[k];i++){//左右边界都不要
int t;
t=a[x+i];
a[x+i]=a[y+i];
a[y+i]=t;
}
}
void dfs(int now,int x){
//cout<<x<<" "<<now<<endl;
if(x==n+){
res+=fac[now];
return ;
}
int pos1=;int pos2=;int cnt=;
for(int i=;i<=num;i+=power[x]){
if(check(i,x)){
cnt++;
if(cnt>=) break;
if(!pos2){
if(!pos1){
pos1=i;
}
else pos2=i;
}
}
}
//cout<<cnt<<" "<<pos1<<" "<<pos2<<endl;
if(cnt>) return ;
if(cnt==){
dfs(now,x+);
}
if(cnt==){
swap(pos1,pos1+power[x-],x-);
dfs(now+,x+);
swap(pos1,pos1+power[x-],x-); }
if(cnt==){
swap(pos1,pos2,x-);
if(check(pos1,x)||check(pos2,x)){
swap(pos1,pos2,x-);
}
else{
dfs(now+,x+);
swap(pos1,pos2,x-);
}
swap(pos1,pos2+power[x-],x-);
if(check(pos1,x)||check(pos2,x)){
swap(pos1,pos2+power[x-],x-);
}
else{
dfs(now+,x+);
swap(pos1,pos2+power[x-],x-);
}
swap(pos1+power[x-],pos2,x-);
if(check(pos1,x)||check(pos2,x)){
swap(pos1+power[x-],pos2,x-);
}
else{
dfs(now+,x+);
swap(pos1+power[x-],pos2,x-);
}
swap(pos1+power[x-],pos2+power[x-],x-);
if(check(pos1,x)||check(pos2,x)){
swap(pos1+power[x-],pos2+power[x-],x-);
}
else{
dfs(now+,x+);
swap(pos1+power[x-],pos2+power[x-],x-);
}
}
}
int main(){
fac[]=;power[]=;
for(int i=;i<=;i++){
fac[i]=fac[i-]*i;
power[i]=power[i-]<<;
}
scanf("%d",&n);
num=qpower(,n);
for(int i=;i<=num;i++){
scanf("%d",&a[i]);
}
dfs(,);
//for(int i=1;i<=15;i++) cout<<power[i]<<" "<<fac[i]<<endl;
//cout<<power[15];
printf("%d",res);
}
丑陋得不能再丑陋的代码
一道看题解后完全自己码出来,调出来的代码,还是很高兴的。
搜索水平还是太弱了啊,考试时都不知道暴力怎么打,一定要提升搜索的水平啊
[sdoi2015]排序(搜索+剪枝优化)的更多相关文章
- BZOJ 3990: [SDOI2015]排序 [搜索]
3990: [SDOI2015]排序 题意:\(2^n\)的一个排列,给你n种操作,第i种把每\(2^{i-1}\)个数看成一段,交换任意两段.问是这个序列有序的操作方案数,两个操作序列不同,当且仅当 ...
- poj 1054 The Troublesome Frog (暴力搜索 + 剪枝优化)
题目链接 看到分类里是dp,结果想了半天,也没想出来,搜了一下题解,全是暴力! 不过剪枝很重要,下面我的代码 266ms. 题意: 在一个矩阵方格里面,青蛙在里面跳,但是青蛙每一步都是等长的跳, 从一 ...
- [bzoj3990][SDOI2015]排序-搜索
Brief Description 小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1<=i<= ...
- BZOJ 3990 [SDOI2015]排序 ——搜索
[题目分析] 可以发现,操作的先后顺序是不影响结果的,那么答案就是n!的和. 可以从小的步骤开始搜索,使得每一个当前最小的块都是上升的数列,然后看看是否可行即可. 复杂度好像是4^n [代码](哪里写 ...
- BZOJ 3990: [SDOI2015]排序(搜索+剪枝)
[SDOI2015]排序 Description 小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1< ...
- 搜索(剪枝优化):HDU 5113 Black And White
Description In mathematics, the four color theorem, or the four color map theorem, states that, give ...
- 图解Leetcode组合总和系列——回溯(剪枝优化)+动态规划
Leetcode组合总和系列--回溯(剪枝优化)+动态规划 组合总和 I 给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 ...
- hdu 5887 搜索+剪枝
Herbs Gathering Time Limit: 3000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)T ...
- 搜索+剪枝——POJ 1011 Sticks
搜索+剪枝--POJ 1011 Sticks 博客分类: 算法 非常经典的搜索题目,第一次做还是暑假集训的时候,前天又把它翻了出来 本来是想找点手感的,不想在原先思路的基础上,竟把它做出来了而且还是0 ...
随机推荐
- url编码问题小计
昨天通过get访问服务器遇到了服务器获取不到参数的问题,最后排查下来是因为url编码的原因,之前使用的是字符串拼接,所以有一些特殊字符如‘%’没有正确的编码, 通过改成各个部分编码,正确获取到数据. ...
- http请求之of_ordering_http_post
//Public function of_ordering_http_post (string as_vipsj,string as_url) returns string //string as_v ...
- kubernetes dashboard访问用户添加权限控制
前面我们在kubernetes dashboard 升级之路一文中成功的将Dashboard升级到最新版本了,增加了身份认证功能,之前为了方便增加了一个admin用户,然后授予了cluster-adm ...
- Jmeter之Linux安装(Xshell),分布式运行Linux作为slave机
甲方爸爸要求,用Linux压测...... 所以在公司服务器Linux上搭建Jmeter 但实际一个Jmeter程序也有程序瓶颈~ 所以在Jmeter瓶颈下,搭建分布式压测系统.(也许可以尝试在一 ...
- Hello World!!!
C #include <stdio.h> int main() #main 入口函数 { printf("Hello,World!"); #printf 函数打印 ; ...
- 12-Perl 时间日期
1.Perl 时间日期本章节介绍 Perl 语言对时间日期的处理.Perl中处理时间的函数有如下几种: time() 函数:返回从1970年1月1日起累计的秒数 localtime() 函数:获取本地 ...
- MVC4学习要点记四
一.使用原生SQL使用EF的一个优点就是自动帮我们生成SQL,这在常规情况下很方便,但有些情况下用EF却不适合.另外还有些特别复杂的语句,利用EF很难生成.所以,EF提供一组方法用来执行原生的SQL. ...
- ThreadLocal的原理与使用
前言 在java web项目中,经常会使用到单例对象,从服务器启动那一时刻就实例化全局对象.然后会对某些全局对象的属性进行修改之类的操作,但是我们知道项目一般都是部署到tomcat.Jboss之类的服 ...
- javascript是一种安全语言
一.简单JavaScript是一个基于Java基本语句和控制流的简单而紧凑的设计,这是学习Java的一个很好的过渡.它的变量类型是弱类型,而不是严格的数据类型.二.力学JavaScript是动态的,可 ...
- 编辑docker容器中的文件
一般docker中没有VI或者其它相应的文本编辑器,为了写个东西安装个vi就可以解决问题,除此之外还有别的办法 登陆docker中找到需要编辑的文件的位置 sudo docker ps -a sudo ...