原文链接https://www.cnblogs.com/zhouzhendong/p/UOJ41.html

题解

首先写个乱搞:

一开始每一行都选择第一个非0元素,然后,我们对这个方案不断做更新,直到任意两行选择的值不同。更新方法:如果有两行选了相同的值,那么让靠前的那行选择后一个非0的值。

交上去。

过了。

wtf?

然后发现证明这个结论我花的时间远远大于AC这题QAQ

现在我们来证明一下:

首先,如果这个算法算出解了,那么肯定合法。这个比较显然就不证明了。

然后,我们来分两步证明一定有解。

接下来我们称让某一行找下一个非0元素这个操作为“弹出这一行的第一个元素”。

引理

  假设当前状态下,我们在所有行选择的元素构成的集合为 S ;设若干次更新更新后的集合为 S' ,那么一定有: $S\subseteq S'$ 。

  证明:每次至少有两个相同我们才让其中一个更新,所以这两行原先的值会被保留。所以满足这个引理。

接下来我们证明一个命题。

命题

  在得到答案之前,1~n 中至少有一种数没有被作为某一行的第一个元素“弹出”过。

  证明:如果任意两行选择的元素都不同,那么就得到方案了。在集合 S 中元素种类变成 n 的时刻,我们就得到了方案。设最后一次加入集合 S 的元素是 x ,那么在整个过程中, x 一定没有作为某一行的第一个元素被弹出过,所以命题得证。

因为在得到答案之前,1~n 中至少有一种数没有被作为某一行的第一个元素“弹出”过,而每一个元素在每一行都会出现一次。考虑那个没有被弹出过的元素,它保证了每一行都不会被弹光,所以一定有解,而且通过这个构造方法可以得到解。

代码

  1. #pragma GCC optimize("Ofast","inline")
  2. #include <bits/stdc++.h>
  3. #define clr(x) memset(x,0,sizeof (x))
  4. #define For(i,a,b) for (int i=a;i<=b;i++)
  5. #define Fod(i,b,a) for (int i=b;i>=a;i--)
  6. #define pb push_back
  7. #define mp make_pair
  8. #define fi first
  9. #define se second
  10. #define _SEED_ ('C'+'L'+'Y'+'A'+'K'+'I'+'O'+'I')
  11. #define outval(x) printf(#x" = %d\n",x)
  12. #define outvec(x) printf("vec "#x" = ");for (auto _v : x)printf("%d ",_v);puts("")
  13. #define outtag(x) puts("----------"#x"----------")
  14. #define outarr(a,L,R) printf(#a"[%d...%d] = ",L,R);\
  15. For(_v2,L,R)printf("%d ",a[_v2]);puts("");
  16. using namespace std;
  17. typedef long long LL;
  18. LL read(){
  19. LL x=0,f=0;
  20. char ch=getchar();
  21. while (!isdigit(ch))
  22. f|=ch=='-',ch=getchar();
  23. while (isdigit(ch))
  24. x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
  25. return f?-x:x;
  26. }
  27. const int N=405;
  28. int T,n,m;
  29. int a[N][N];
  30. int p[N],id[N],cnt[N];
  31. bool cmp(int a,int b){
  32. return p[a]<p[b];
  33. }
  34. int Getnxt(int i,int &p){
  35. while (!a[i][p]&&p<=m)
  36. p++;
  37. return p<=m;
  38. }
  39. void solve(){
  40. n=read(),m=read();
  41. clr(a),clr(p);
  42. For(i,1,n)
  43. For(j,1,m)
  44. a[i][j]=read();
  45. For(i,1,n)
  46. Getnxt(i,p[i]=1);
  47. while (1){
  48. clr(cnt);
  49. int flag=0;
  50. For(i,1,n){
  51. cnt[a[i][p[i]]]++,id[i]=i;
  52. if (cnt[a[i][p[i]]]>1)
  53. flag=1;
  54. }
  55. if (!flag)
  56. break;
  57. sort(id+1,id+n+1,cmp);
  58. For(i,1,n)
  59. if (cnt[a[id[i]][p[id[i]]]]>1){
  60. if (!Getnxt(id[i],++p[id[i]])){
  61. puts("\(^o^)/");
  62. return;
  63. }
  64. break;
  65. }
  66. }
  67. For(i,1,n)
  68. printf("%d ",a[i][p[i]]);
  69. puts("");
  70. }
  71. int main(){
  72. T=read();
  73. while (T--)
  74. solve();
  75. return 0;
  76. }

  

UOJ#41. 【清华集训2014】矩阵变换 构造的更多相关文章

  1. UOJ.41.[清华集训2014]矩阵变换(稳定婚姻)

    题目链接 稳定婚姻问题:有n个男生n个女生,每个男/女生对每个女/男生有一个不同的喜爱程度.给每个人选择配偶. 若不存在 x,y未匹配,且x喜欢y胜过喜欢x当前的配偶,y喜欢x也胜过y当前的配偶 的完 ...

  2. bzoj 3816&&uoj #41. [清华集训2014]矩阵变换

    稳定婚姻问题: 有n个男生,n个女生,所有女生在每个男生眼里有个排名,反之一样. 将男生和女生两两配对,保证不会出现婚姻不稳定的问题. 即A-1,B-2 而A更喜欢2,2更喜欢A. 算法流程: 每次男 ...

  3. [BZOJ3816][清华集训2014]矩阵变换(稳定婚姻问题)

    3816: 矩阵变换 Time Limit: 10 Sec  Memory Limit: 512 MBSubmit: 803  Solved: 578[Submit][Status][Discuss] ...

  4. uoj #46[清华集训2014]玄学

    uoj 因为询问是关于一段连续区间内的操作的,所以对操作构建线段树,这里每个点维护若干个不交的区间,每个区间\((l,r,a,b)\)表示区间\([l,r]\)内的数要变成\(ax+b\) 每次把新操 ...

  5. uoj 41 【清华集训2014】矩阵变换 婚姻稳定问题

    [清华集训2014]矩阵变换 Time Limit: 20 Sec  Memory Limit: 256 MB 题目连接 http://uoj.ac/problem/41 Description 给出 ...

  6. AC日记——【清华集训2014】奇数国 uoj 38

    #38. [清华集训2014]奇数国 思路: 题目中的number与product不想冲: 即为number与product互素: 所以,求phi(product)即可: 除一个数等同于在模的意义下乘 ...

  7. [UOJ#274][清华集训2016]温暖会指引我们前行

    [UOJ#274][清华集训2016]温暖会指引我们前行 试题描述 寒冬又一次肆虐了北国大地 无情的北风穿透了人们御寒的衣物 可怜虫们在冬夜中发出无助的哀嚎 “冻死宝宝了!” 这时 远处的天边出现了一 ...

  8. UOJ#46. 【清华集训2014】玄学

    传送门 分析 清华集训真的不是人做的啊嘤嘤嘤 我们可以考虑按操作时间把每个操作存进线段树里 如果现在点x正好使一个整块区间的右端点则更新代表这个区间的点 我们不难发现一个区间会因为不同的操作被分成若干 ...

  9. 清华集训2014 sum

    清华集训2014sum 求\[∑_{i=1}^{n}(-1)^{⌊i√r⌋}\] 多组询问,\(n\leq 10^9,t\leq 10^4, r\leq 10^4\). 吼题解啊 具体已经讲得很详细了 ...

随机推荐

  1. JMeter的介绍和简单使用

    Apache官网(https://jmeter.apache.org/)对JMeter的解释: Apache JMeter™ Apache JMeter™应用程序是开源软件,   为负载功能和性能测试 ...

  2. js 遍历集合删除元素

    js 遍历集合删除元素 /** * 有效的方式 - 改变下标,控制遍历 */ for (var i = 0; i < arr.length; i++) { if (...) { arr.spli ...

  3. Redis源码 - 事件管理

    Redis 的事件分类 分类 描述 定时器 线程内定时响应,更新缓存时间.关闭非活动的客户端连接等等 pipe 线程间通信,用于其他线程通知主线程退出aeApiPoll() unixsocket 本地 ...

  4. 【C++笔记】析构函数(destructor)

    “析构函数”是构造函数的反向函数. 在销毁(释放)对象时将调用它们. 通过在类名前面放置一个波形符 (~) 将函数指定为类的析构函数.   声明析构函数   析构函数是具有与类相同的名称但前面是波形符 ...

  5. 统一配置管理 windows linux ide maven gradle docker 【渐进式备份更新~~】

    Tips 系统盘放轻量配置(%HOMEPATH%),仓库盘放大容量文件(自己维护一份 语义化目录结构.txt). Tips               系统盘放 不经常写操作的文件(除轻量配置)    ...

  6. WordPress Plugin Form Maker [CSRF → LFI] vulnerable 2019-03-17

    # Title: Form Maker by WD [CSRF → LFI]# Date: 2019-03-17# Exploit Author: Panagiotis Vagenas# Vendor ...

  7. APPLE-SA-2019-3-27-1 watchOS 5.2

    APPLE-SA-2019-3-27-1 watchOS 5.2 watchOS 5.2 is now available and addresses the following: CFStringA ...

  8. hibernate之一对多,多对一

    配置文件 <!--一对多--><!--name:集合属性名字 column:外键列名 class:与它相关的对象的完整列名 cascade:级联操作:分3种 save-update: ...

  9. c++ 入门 之 hello world 和基本语法

    1,linux系统上如何跑c++程序 1,vim一个hello.cpp,内容如下: #include <iostream> using namespace std; int main() ...

  10. C#创建控制台项目引用Topshelf的方式,部署windows服务。

    上一篇是直接创建windows service服务来处理需求.调试可能会麻烦一点.把里面的逻辑写好了.然后受大神指点,用Topshelf会更好一些. 来公司面试的时候问我,为什么要用stringbui ...