1. 程式人生 > >[CC-SEAPERM2]Sereja and Permutations

[CC-SEAPERM2]Sereja and Permutations

tmp auto clas line lag 多個 個數 cal second

[CC-SEAPERM2]Sereja and Permutations

題目大意:

有一個\(n(n\le300)\)排列\(p\),將其中一個元素\(p_i\)拿掉,然後將原來大於\(p_i\)的元素減一,這樣就得到一個新的排列。

\(p\)中每一個數拿掉之後都會得到一個新的排列,這樣就得到了\(n\)個新的排列。

現在給出最後得到的\(n\)個新的排列(順序隨機),請求出原來的排列。如果有多個解,輸出字典序最小的解。保證至少有一個解。

思路:

枚舉哪一個排列被刪掉了\(p_1\),那麽剩下排列的第一個數,要麽是\(p_1\),要麽是\(p_1-1\)。(如果剩下不止兩種數,或者相差超過\(1\)

,說明被刪去\(p_1\)的不可能是這個排列。)

這樣,我們就可以得到\(p_1\),從而得到初始的排列,但是我們還要刪去每一個數看看是否和給你的排列一樣來驗證。做法是hash+map。

時間復雜度\(\mathcal O(n^3)\)

源代碼:

#include<map>
#include<cstdio>
#include<cctype>
#include<climits>
#include<algorithm>
inline int getint() {
    register char ch;
    while(!isdigit(ch=getchar()));
    register int x=ch^'0';
    while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
    return x;
}
typedef unsigned long long uint64;
const int N=301;
const uint64 base=31;
bool have_ans;
int n,a[N][N],b[N],ans[N];
std::map<uint64,int> map;
inline uint64 hash(int a[]) {
    uint64 ret=0;
    for(register int i=1;i<n;i++) {
        ret=ret*base+a[i];
    }
    return ret;
}
inline bool check() {
    for(register int i=1;i<=n;i++) {
        if(b[i]<ans[i]) return true;
        if(b[i]>ans[i]) return false;
    }
    return false;
}
inline void upd() {
    if(!have_ans||check()) {
        have_ans=true;
        for(register int i=1;i<=n;i++) ans[i]=b[i];
    }
}
int main() {
    for(register int T=getint();T;T--) {
        n=getint();
        if(n==1) {
            puts("1");
            return 0;
        }
        for(register int i=1;i<=n;i++) {
            for(register int j=1;j<n;j++) {
                a[i][j]=getint();
            }
        }
        have_ans=false;
        for(register int i=1;i<=n;i++) {
            int max[2]={0,0};
            bool three=false;
            for(register int j=1;j<=n;j++) {
                if(i!=j) {
                    int tmp=a[j][1];
                    if(tmp==max[0]||tmp==max[1]) continue;
                    for(register int k=0;k<2;k++) {
                        if(tmp>max[k]) std::swap(max[k],tmp);
                    }
                    three|=tmp;
                }
            }
            if(three||(max[1]&&max[0]-max[1]!=1)) continue;
            for(register int val=max[0];val<=max[0]+1;val++) {
                for(register int i=1;i<=n;i++) map[hash(a[i])]++;
                b[1]=val;
                for(register int j=2;j<=n;j++) b[j]=a[i][j-1]+(a[i][j-1]>=b[1]);
                for(register int i=1;i<=n;i++) {
                    uint64 ret=0;
                    for(register int j=1;j<=n;j++) {
                        if(i!=b[j]) ret=(uint64)ret*base+b[j]-(b[j]>i);
                    }
                    map[ret]--;
                }
                bool flag=true;
                for(auto &i:map) {
                    if(i.second!=0) flag=false;
                }
                map.clear();
                if(flag) upd();
            }
        }
        for(register int i=1;i<=n;i++) {
            printf("%d%c",ans[i]," \n"[i==n]);
        }
    }
    return 0;
}

[CC-SEAPERM2]Sereja and Permutations