<h1>题目描述</h1>

已知序列 $S=&#123;0,1,\cdots ,n-1&#125;$,序列里有 $n$ 个数,从 $0$ 到 $n-1$。定义两个数 $x,y$ 的距离 $D(x,y) = min&#123;|x-y|,N-|x-y|&#125;$.
定义序列 S 的一个排列 T ,那么这两个序列的距离序列 $Q(S,T) = &#123;D(S_0,T_0),D(S_1,T_1),\cdots,D(S_{n-1},T_{n-1}&#125;$
现在知道距离序列,求出可能的 $T$ 中字典序最小的那个。
其中 $n \leq 10^4$。

<h1>题解</h1>

我们首先考虑建出一张二分图 $G$,边 $x,y$ 存在的意义是 $T$ 的第 $x$ 个元素可以放置 $y$.
那么我们建完这张二分图后,如果最大匹配数为 $n$,那么就存在解。
我们考虑如何输出字典序最小的解。
具体来说记录每个点匹配到了哪个点,每次优先遍历编号大的点,这样最后得到的序列就是字典序最小的了。
时间复杂度 $O(n^2)$

<h1>代码</h1>

#include <algorithm>
#include <iostream>
#include <cstring>
#include <climits>
#include <cstdio>
#include <vector>
#include <cmath>
#include <queue>
#include <stack>
#include <map>
#include <set>
#define Re register
#define LL long long
#define U unsigned
#define FOR(i,a,b) for(Re int i = a;i <= b;++i)
#define ROF(i,a,b) for(Re int i = a;i >= b;--i)
#define CLR(i,a) memset(i,a,sizeof(i))
#define BR printf("--------------------n")
#define DEBUG(x) std::cerr << #x << '=' << x << std::endl

const int MAXN = 10000+5;

struct Node{
    struct Edge *firstEdge;
    Node pre,suf;bool vis;
    int num;
}node[MAXN];

struct Edge{
    Node s,t;
    Edge *next;
}pool[MAXN<<1],*frog = pool;

Edge New(Node s,Node *t){
    Edge *ret = ++frog;
    *ret = (Edge){s,t,s->firstEdge};
    return ret;
}

inline void add(int u,int v){
    node[u].firstEdge = New(&node[u],&node[v]);
}

int N,d[MAXN];

bool dfs(Node *v){
    //DEBUG(v->num);
    for(Edge *e = v->firstEdge;e;e = e->next){
        //DEBUG(e->t->num);
        if(e->t->vis) continue;
        e->t->vis = true;
        if(!e->t->pre || dfs(e->t->pre)){
            e->t->pre = v;
            v->suf = e->t;
            return true;
        }
    }
    return false;
}

inline int solve(){
    int cnt = 0;
    ROF(i,N-1,0){
        FOR(j,0,N) node[j].vis = false;
        cnt += dfs(&node[i]);
    }
    return cnt;
}

int main(){
    scanf("%d",&N);
    FOR(i,0,N-1) scanf("%d",d+i);
    FOR(i,0,N-1){
        ROF(j,N-1,0){
            if(std::min(std::abs(i-j),N-std::abs(i-j)) == d[i]){
                add(i,j);
                //printf("%d %dn",i,j);
            }
        }
    }
    FOR(i,0,N) node[i].num = i;
    if(solve() == N){
        FOR(i,0,N-1) printf("%d%c",node[i].suf->num,(i == N-1) ? 'n' : ' ');
    }
    else{
        puts("No Answer");
    }
    return 0;
}
Last modification:April 7th, 2020 at 10:14 pm
如果觉得我的文章对你有用,请随意赞赏