title
BZOJ 1562
LUOGU 1963
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。BZOJ又直接把pdf的图片粘过来了。
analysis
这道题很妙啊!把一道看起来挺数论的题搞成二分图匹配。
抱歉,由于我们两个是在讨论网络流,所以,又在想这道题的网络流算法。
我想出:直接跑最大流,在选方案的时候,每个点都选相对字典序较小的那个点,应该就可以了吧。
\(Chdy\) 指出:万一你选了字典序较小的点,破坏了最大流呢?
我:...
然后,\(Chdy\) 想到了每个原数列最多可以连两条边,连向变换后的两个点,为什么?自己推这个式子:\(D(x,y)=min\left\{∣x−y∣,N−∣x−y∣\right\}\)。
随后他想到的一些算法,都无法处理在选择字典序较小的点的同时保证最大流仍成立,所以...我们放弃了网络流写法,开心地奔向了匈牙利算法, ̄▽ ̄。
我想到的是,那就直接每确定一个点,跑一遍匹配。
\(Chdy\) :复杂度不够啊,能拿 \(70pts\) 就不错了。
我:...(你说怎么办呀...)
\(Chdy\):我觉得应该一边匹配,一边修正,不过匈牙利算法的复杂度应该是 \(O(N^3)\) 的吧,不太行。
我:邻接矩阵最坏\(O(N^3)\),邻接表\(O(NM)\)。
\(Chdy\):那 OK 啦,可以看题解检验我们算法的正确性了。
于是翻开 \(BYVoid\)的 \(blog\),发现家宝写了四种写法,惊呼:神犇就是这样炼成的!
正解是什么倒序匹配,于是我便瞎证明一波,最后被吐槽:这不是显然正确吗。
好了,放代码吧,我可只写了倒序匹配这一种算法,别嫌弃。
神犇那里有四种解法:BYVoid。
code
#include<bits/stdc++.h> using namespace std; const int maxn=1e5+10; char buf[1<<15],*fs,*ft; inline char getc() { return (ft==fs&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),ft==fs))?0:*fs++; } template<typename T>inline void read(T &x) { x=0; T f=1, ch=getchar(); while (!isdigit(ch) && ch^'-') ch=getchar(); if (ch=='-') f=-1, ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48), ch=getchar(); x*=f; } template<typename T>inline void write(T x) { if (!x) { putchar('0'); return ; } if (x<0) putchar('-'), x=-x; T num=0, ch[20]; while (x) ch[++num]=x%10+48, x/=10; while (num) putchar(ch[num--]); } int ver[maxn],Next[maxn],head[maxn],len; inline void add(int x,int y) { ver[++len]=y,Next[len]=head[x],head[x]=len; } int match[maxn]; bool vis[maxn]; inline bool dfs(int x) { for (int i=head[x]; i; i=Next[i]) { int y=ver[i]; if (!vis[y]) { vis[y]=1; if (!match[y] || dfs(match[y])) { match[y]=x; match[x]=y; return true; } } } return false; } int s[maxn][2]; int main() { int n;read(n); for (int i=0,c; i<n; ++i) { read(c); int t1=i-c; if (t1<0) t1+=n; int t2=i+c; if (t2>n-1) t2-=n; if (t1<t2) s[i][0]=t1,s[i][1]=t2; else s[i][0]=t2,s[i][1]=t1; add(i,s[i][1]+n); add(i,s[i][0]+n); } int ans=0; for (int i=n-1; i>=0; --i) { memset(vis,0,sizeof(vis)); if (dfs(i)) ++ans; } if (ans<n) return puts("No Answer"),0; for (int i=0; i<n; ++i) write(match[i]-n),putchar(' '); return 0; }