原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ41.html
题解
首先写个乱搞:
一开始每一行都选择第一个非0元素,然后,我们对这个方案不断做更新,直到任意两行选择的值不同。更新方法:如果有两行选了相同的值,那么让靠前的那行选择后一个非0的值。
交上去。
过了。
wtf?
然后发现证明这个结论我花的时间远远大于AC这题QAQ
现在我们来证明一下:
首先,如果这个算法算出解了,那么肯定合法。这个比较显然就不证明了。
然后,我们来分两步证明一定有解。
接下来我们称让某一行找下一个非0元素这个操作为“弹出这一行的第一个元素”。
引理
假设当前状态下,我们在所有行选择的元素构成的集合为 S ;设若干次更新更新后的集合为 S' ,那么一定有: $Ssubseteq S'$ 。
证明:每次至少有两个相同我们才让其中一个更新,所以这两行原先的值会被保留。所以满足这个引理。
接下来我们证明一个命题。
命题
在得到答案之前,1~n 中至少有一种数没有被作为某一行的第一个元素“弹出”过。
证明:如果任意两行选择的元素都不同,那么就得到方案了。在集合 S 中元素种类变成 n 的时刻,我们就得到了方案。设最后一次加入集合 S 的元素是 x ,那么在整个过程中, x 一定没有作为某一行的第一个元素被弹出过,所以命题得证。
因为在得到答案之前,1~n 中至少有一种数没有被作为某一行的第一个元素“弹出”过,而每一个元素在每一行都会出现一次。考虑那个没有被弹出过的元素,它保证了每一行都不会被弹光,所以一定有解,而且通过这个构造方法可以得到解。
代码
#pragma GCC optimize("Ofast","inline") #include <bits/stdc++.h> #define clr(x) memset(x,0,sizeof (x)) #define For(i,a,b) for (int i=a;i<=b;i++) #define Fod(i,b,a) for (int i=b;i>=a;i--) #define pb push_back #define mp make_pair #define fi first #define se second #define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I') #define outval(x) printf(#x" = %d ",x) #define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("") #define outtag(x) puts("----------"#x"----------") #define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R); For(_v2,L,R)printf("%d ",a[_v2]);puts(""); using namespace std; typedef long long LL; LL read(){ LL x=0,f=0; char ch=getchar(); while (!isdigit(ch)) f|=ch=='-',ch=getchar(); while (isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar(); return f?-x:x; } const int N=405; int T,n,m; int a[N][N]; int p[N],id[N],cnt[N]; bool cmp(int a,int b){ return p[a]<p[b]; } int Getnxt(int i,int &p){ while (!a[i][p]&&p<=m) p++; return p<=m; } void solve(){ n=read(),m=read(); clr(a),clr(p); For(i,1,n) For(j,1,m) a[i][j]=read(); For(i,1,n) Getnxt(i,p[i]=1); while (1){ clr(cnt); int flag=0; For(i,1,n){ cnt[a[i][p[i]]]++,id[i]=i; if (cnt[a[i][p[i]]]>1) flag=1; } if (!flag) break; sort(id+1,id+n+1,cmp); For(i,1,n) if (cnt[a[id[i]][p[id[i]]]]>1){ if (!Getnxt(id[i],++p[id[i]])){ puts("(^o^)/"); return; } break; } } For(i,1,n) printf("%d ",a[i][p[i]]); puts(""); } int main(){ T=read(); while (T--) solve(); return 0; }