zoukankan      html  css  js  c++  java
  • [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;
    }
    
    Miemeng真的蒻
  • 相关阅读:
    SpringSecurity 框架学习 3
    SpringSecurity 框架学习 项目创建
    nginx 限制ip访问
    nginx 负载均衡,后端服务获取不到域名问题
    Linux 安装 Nginx
    Linux 常用命令
    springcloud 服务追踪
    Hystrix 服务容错
    Scrum立会报告+燃尽图(十二月十日总第四十一次):用户推广
    Final发布:文案+美工展示博客
  • 原文地址:https://www.cnblogs.com/kalginamiemeng/p/11160561.html
Copyright © 2011-2022 走看看