BZOJ1562: [NOI2009]变换序列

1562: [NOI2009]变换序列

Time Limit: 5 Sec  Memory Limit: 64 MB
Submit: 2030  Solved: 1026
[Submit][Status][Discuss]

Description

Input

Output

Sample Input

5
1 1 2 2 1

Sample Output

1 2 4 0 3

HINT

30%的数据中N≤50;
60%的数据中N≤500;
100%的数据中N≤10000。

思路{

  容易想到,问题的答案就是i和d(i,T)所限制的点连边做最大匹配,

  问题是怎么保证字典序呢?

  然后发现如果从后开始做匈牙利的话根据匈牙利的思想(

  能上就上,否则创造机会上.若能匹配表示匹配当前字典序最大,

  否则为了满足当前字典序更改后面的节点的匹配状况)是能够满足的.

  直接上匈牙利就可以了.

}

 

#include<bits/stdc++.h>
#define LL long long
#define RG register
#define il inline
#define N 100010
using namespace std;
int n,d[N],BL[N],Ans[N];bool used[N];
int dd(int x,int y){return min(n-abs(x-y),abs(x-y));}
struct ed{int nxt,to;}e[N*2];
int head[N],tot;
void link(int u,int v){e[tot].nxt=head[u];e[tot].to=v;head[u]=tot++;}
bool find(int u){
  for(int i=head[u];i!=-1;i=e[i].nxt)
  if(!used[e[i].to]){
    int v=e[i].to;
    used[v]=true;
    if((!BL[v])||find(BL[v])){
      BL[v]=u;
      return true;
    }
  }return false;
}
int main(){
  memset(head,-1,sizeof(head));
  scanf("%d",&n);
  for(int i=0;i<n;++i){
    scanf("%d",&d[i]);
    int x=i+d[i],y=i-d[i];
    x%=n,y=(y+n)%n;
    if(dd(x,i)!=d[i])x=-1;
    if(dd(y,i)!=d[i])y=-1;
    if(x>y)swap(x,y);
    if(y!=-1)link(i,y);
    if(x!=-1)link(i,x);
  }
  for(int i=n-1;i!=-1;i--){
    memset(used,0,sizeof(used));
    if(find(i)!=1)cout<<"No Answer\n",exit(0);
  }for(int i=0;i<n;++i)Ans[BL[i]]=i;
  for(int i=0;i<n-1;++i)cout<<Ans[i]<<" ";
  cout<<Ans[n-1];
  return 0;
}

 

posted @ 2017-09-05 00:00  QYP_2002  阅读(155)  评论(0编辑  收藏  举报