zoukankan      html  css  js  c++  java
  • [SDOI2015][bzoj3990] 序列 [搜索]

    题面

    传送门

    思路

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

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

    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;
    }
    
  • 相关阅读:
    hdu 1017 A Mathematical Curiosity 解题报告
    hdu 2069 Coin Change 解题报告
    hut 1574 组合问题 解题报告
    hdu 2111 Saving HDU 解题报
    hut 1054 Jesse's Code 解题报告
    hdu1131 Count the Trees解题报告
    hdu 2159 FATE 解题报告
    hdu 1879 继续畅通工程 解题报告
    oracle的系统和对象权限
    oracle 自定义函数 返回一个表类型
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/9255850.html
Copyright © 2011-2022 走看看