<h1>题目描述</h1>
已知序列 $S={0,1,\cdots ,n-1}$,序列里有 $n$ 个数,从 $0$ 到 $n-1$。定义两个数 $x,y$ 的距离 $D(x,y) = min{|x-y|,N-|x-y|}$.
定义序列 S 的一个排列 T ,那么这两个序列的距离序列 $Q(S,T) = {D(S_0,T_0),D(S_1,T_1),\cdots,D(S_{n-1},T_{n-1}}$
现在知道距离序列,求出可能的 $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; }