【hrbust2294】方方正正

时间:2022-06-27 13:22:43

题意

哈理工2016级新生程序设计全国邀请赛C题

一个r行c列的01矩阵,告诉你每行的和、每列的和,问是否存在这样的矩阵?

题解

首先,行和和列和之和要相等,否则一定是NO。

然后根据Gale-Ryser定理判断存在性:

求出\(R^*=(r_1^*,r_2^*,...,r_m^*),r_i^*=行和大于等于i的行数\),

只要\(R^*\preceq S\)就存在,这里的S就是列和向量。

二元操作符\(\preceq\)的定义是:向量x的前i大的数之和总是比向量y的前i大的数之和要小或者相等,那么\(x\preceq y\)。

代码

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define N 100006
int i,m,n;
long long rs,cs,r[N],c[N],w[N];
int main(){
while(~scanf("%d%d",&m,&n)){//m行n列
rs=cs=0;
memset(w,0,sizeof w); for(i=1;i<=m;i++){
scanf("%d",&r[i]);
rs+=r[i];
w[r[i]]++;//w[i]:行和为i的有几个
} for(i=1;i<=n;i++){
scanf("%d",&c[i]);
cs+=c[i];
} if(rs!=cs){
puts("NO");
continue;
} sort(c+1,c+1+n,greater<long long>()); for(i=n;i;i--)w[i]+=w[i+1];//w[i]:行和大于等于i的有几个 for(i=1;i<=n;i++){
c[i]+=c[i-1];
w[i]+=w[i-1];
if(c[i]>w[i])//w就是R*,若c[i]>w[i]表明R*不能盖过S
break;
} if(i==n+1) puts("YES");
else puts("NO");
}
return 0;
}