BZOJ 3990 排序
【题目描述】:
小A有一个1~2N的排列A[1..2N],他希望将数组A从小到大排序。小A可以执行的操作有N种,每种操作最多可以执行一次。对于所有的i(1<=i<=N),第i种操作为:将序列从左到右划分成2N-i+1段,每段恰好包含2i-1个数,然后整体交换其中的两段。小A想知道可以将数组A从小到大排序的不同的操作序列有多少个。小A认为两个操作序列不同,当且仅当操作的个数不同,或者至少一个操作不同(种类不同或者操作的位置不同)。
下面是一个操作示例:
N=3,初始排列A[1..8]为[3,6,1,2,7,8,5,4]。
第一次操作:执行第3种操作,交换A[1..4]和A[5..8],交换后的A[1..8]为[7,8,5,4,3,6,1,2];
第二次操作:执行用第1种操作,交换A[3]和A[5],交换后的A[1..8]为[7,8,3,4,5,6,1,2];
第三次操作:执行用第2种操作,交换A[1..2]和A[7..8],交换后的A[1..8]为[1,2,3,4,5,6,7,8]。
【输入格式】
第一行,一个整数N。
第二行,2N个整数,A[1]、A[2]…A[2N]。
【输出格式】
一行,一个整数,表示可以将数组A从小到大排序的不同的操作序列的个数。
【样例输入】
3
7 8 5 6 1 2 4 3
【样例输出】
6
【数据规模和约定】
对于30%的数据,1<=N<=4;
对于全部的数据,1<=N<=12。
题解:
15%算法:输出阶乘。
这个代码就不发了,应该没有人不会打阶乘。
这是一个非常迷的东西,为什么输出阶乘能得分呢?首先我们发现,如果已经找到了一种交换方法,那么我们任意交换其中的操作,这样也能得到最终的序列
证明的话,一下摘自某大佬博客:
假设我现在第一次换a,b ,第二次换c,d 且a比c长
那么cd完全被包含和完全无交集肯定不影响。
现在假设c被a包含,d和b分开
那么可以把操作c~d改为操作 (c在b种对应位置)~d
所以会有一个阶乘。如果你看出来了,这很方便你qj测试点。
当然我们练习时需要打正解,下面是100%算法:
上面我们已经知道了这条性质,那么下面的问题就是如何找到这样的一组操作
我们从短的区间2i枚举,如果有一段长度为2i+1的序列并不是公差为1的递增区间,我们就记录一下,
如果这样的区间大于两段,直接return就好。
如果没有。。。你啥都做不了,接着搜下一段长度的区间
如果只有一段,段内直接交换即可
如果有两段,那么需要判断4种情况进行dfs
这四种情况是:前一段的前一段和后一段的前一段,前一段的后一段和后一段的前一段,前一段的前一段和后一段的后一段,前一段的后一段和后一段的前一段。
感谢barca友情提供
废话不说,上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
using namespace std;
ll n,a[<<],js[],m,ans=;
bool judge(ll l,ll r){
for(ll i=l;i<r;i++)
if(a[i+]!=a[i]+)
return false;
return true;
}
void change(ll x,ll y,ll l){
for(ll i=x,j=y;l;l--,i++,j++)
swap(a[i],a[j]);
}
void dfs(ll x,ll y){
if(x==n){
ans+=js[y];
return ;
}
ll sum=,temp[],p=<<x+;
for(ll i=;i<=m;i+=p){
if(judge(i,i+p-)) continue;
temp[++sum]=i;
if(sum==) return ;
}
if(sum>) return ;
if(!sum){
dfs(x+,y);
return ;
}
if(sum==){
change(temp[sum],temp[sum]+(<<x),<<x);
if(judge(temp[sum],temp[sum]+p-)) dfs(x+,y+);
change(temp[sum],temp[sum]+(<<x),<<x);
return ;
}
if(sum==){
change(temp[sum-],temp[sum],<<x);
if(judge(temp[sum-],temp[sum-]+p-)&&judge(temp[sum],temp[sum]+p-))
dfs(x+,y+);
change(temp[sum-],temp[sum],<<x); change(temp[sum-],temp[sum]+(<<x),<<x);
if(judge(temp[sum-],temp[sum-]+p-)&&judge(temp[sum],temp[sum]+p-))
dfs(x+,y+);
change(temp[sum-],temp[sum]+(<<x),<<x); change(temp[sum-]+(<<x),temp[sum],<<x);
if(judge(temp[sum-],temp[sum-]+p-)&&judge(temp[sum],temp[sum]+p-))
dfs(x+,y+);
change(temp[sum-]+(<<x),temp[sum],<<x); change(temp[sum-]+(<<x),temp[sum]+(<<x),<<x);
if(judge(temp[sum-],temp[sum-]+p-)&&judge(temp[sum],temp[sum]+p-))
dfs(x+,y+);
change(temp[sum-]+(<<x),temp[sum]+(<<x),<<x);
}
}
int main(){
scanf("%lld",&n);
js[]=,m=<<n;
for(ll i=;i<=n;i++)
js[i]=js[i-]*i;
for(ll i=;i<=m;i++)
scanf("%lld",&a[i]);
dfs(,);
printf("%lld\n",ans);
return ;
}
BZOJ 3990 排序的更多相关文章
- 【搜索】BZOJ 3990: 【Sdoi 2015】排序
3990: [SDOI2015]排序 Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 336 Solved: 164[Submit][Status][ ...
- BZOJ 3990 [SDOI 2015] 排序 解题报告
这个题哎呀...细节超级多... 首先,我猜了一个结论.如果有一种排序方案是可行的,假设这个方案是 $S$ . 那么我们把 $S$ 给任意重新排列之后,也必然可以构造出一组合法方案来. 于是我们就可以 ...
- BZOJ 3990: [SDOI2015]排序 [搜索]
3990: [SDOI2015]排序 题意:\(2^n\)的一个排列,给你n种操作,第i种把每\(2^{i-1}\)个数看成一段,交换任意两段.问是这个序列有序的操作方案数,两个操作序列不同,当且仅当 ...
- BZOJ.3990.[SDOI2015]排序(DFS)
题目链接 操作序列的顺序显然是无关的,所以只需按特定顺序求出一个长度为\(l\)的操作序列,它对答案的贡献为\(l!\). 我们从小到大枚举所有选择.若当前为第\(i\)个,如果有一段长度为\(2^i ...
- BZOJ 3990: [SDOI2015]排序(搜索+剪枝)
[SDOI2015]排序 Description 小A有一个1-2^N的排列A[1..2^N],他希望将A数组从小到大排序,小A可以执行的操作有N种,每种操作最多可以执行一次,对于所有的i(1< ...
- BZOJ 3990 [SDOI2015]排序
题解: 首先很容易看出各个操作是互不影响的,即对于一个合法的操作序列,我们可以任意交换两个操作的位置而不影响合法性. 因此我们可以忽略操作先后的影响,只考虑这个操作是否会出现在操作序列中. 如果用2n ...
- BZOJ 3990 [SDOI2015]排序 ——搜索
[题目分析] 可以发现,操作的先后顺序是不影响结果的,那么答案就是n!的和. 可以从小的步骤开始搜索,使得每一个当前最小的块都是上升的数列,然后看看是否可行即可. 复杂度好像是4^n [代码](哪里写 ...
- [BZOJ 1552] 排序机械臂
Splay大法是坠吼滴! 1552: [Cerc2007]robotic sort Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 436 Solved: ...
- BZOJ 4552 排序 Heoi2016
记得当年省选的时候 这道题连暴力都没写对(尴尬ing) (当年天真的认为sort是左闭右闭的hhhhhh) 思路: 首先 二分答案 线段树 首先二分答案,然后需要知道进行m次排序后p位置上的数字是否大 ...
随机推荐
- HTML精确定位:scrollLeft,scrollWidth,clientWidth,offsetWidth完全详细的说明
HTML:scrollLeft,scrollWidth,clientWidth,offsetWidth具体指完全解释究竟哪里的距离scrollHeight: 获取对象的高度滚动. scrollLe ...
- STL 中间< 超载
相同的代码,mingw能够执行,vs不能执行. vs报告错误: watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvY2h1Y2h1cw==/font/5a6L5 ...
- QRCode二维码生成方案及其在带LOGO型二维码中的应用(2)
原文:QRCode二维码生成方案及其在带LOGO型二维码中的应用(2) 续前:QRCode二维码生成方案及其在带LOGO型二维码中的应用(1) http://blog.csdn.net/johnsu ...
- 通通WPF随笔(4)——通通手写输入法(基于Tablet pc实现)
原文:通通WPF随笔(4)--通通手写输入法(基于Tablet pc实现) 从我在博客园写第一篇博客到现在已经有1年半了,我的第一篇博客写的就是手写识别,当时,客户需求在应用中加入手写输入功能,由于第 ...
- WPF 数据库增删改查
<Window x:Class="DataBindingExam.MainWindow" xmlns="http://schemas.microsof ...
- WPF应用无法使用Snoop分析的解决办法
如果WPF程序是以管理员身份启动的,Snoop不是用管理员身份启动,那就不行. 用管理员身份启动snoop,就可以了. 管理员身份启动cmd,然后启动snoop,ok.
- win10 uwp 如何判断一个对象被移除
原文:win10 uwp 如何判断一个对象被移除 有时候需要知道某个元素是否已经被移除,在优化内存的时候,有时候无法判断一个元素是否在某个地方被引用,就需要判断对象设置空时是否被回收. 本文告诉大家一 ...
- 【shell】gerrit同步备份脚本的实现
本期分享下gerrit如何实现备份,由于之前的一台代码服务器直接down掉,所以为了以防万一,开始备份gerrit数据,有人说,gerrit不过是个审查代码的工具,备份这个做什么,git是分布式代码管 ...
- Win10《芒果TV》商店版更新v3.2.1:优化手机版卡顿,修复推送故障
此版本是小版本更新,主要是修复上一版本发布后暴露的部分体验问题,以免进一步扩大影响,小幅修复后更新上线. 芒果TV UWP V3.2.1更新内容清单: 1.优化和修复列表预加载机制的本地保存丢失导致的 ...
- 【Qt】无边框窗体中带有ActiveX组件时的一个BUG
无意中发现的一个BUG,Qt5.1.1正式版首先创建一个GUI工程,拖入一个QAxWidget控件(为了使ActiveX生效,需要在.pro文件中加入CONFIG += qaxcontainer)接着 ...