BZOJ1562: [NOI2009]变换序列
1562: [NOI2009]变换序列
Time Limit: 5 Sec Memory Limit: 64 MBSubmit: 2030 Solved: 1026
[Submit][Status][Discuss]
Description
Input
Output
Sample Input
5
1 1 2 2 1
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; }