[AGC018B] Sports Festival 解题记录
好水的蓝题
题意简述
一场运动会有
M
M
M 个项目,
N
N
N 个人参加,你可以关闭至多
M
−
1
M-1
M−1 项目使其不能被参加,其中第
i
i
i 个人会优先参加第
a
i
,
j
a_{i,j}
ai,j个项目(如果第
a
i
,
j
a_{i,j}
ai,j 个项目被关闭了,那么就参加第
a
i
,
j
+
1
a_{i,j+1}
ai,j+1 个,
j
j
j 从
1
1
1 开始)。
现求使参加人数最多的项目的人数最少的关闭方案,输出最少人数。
题目分析
这道题首先不要被题目中的“最多的最少”给迷惑了,其实观察数据范围就可以发现,该题目支持
O
(
N
2
×
M
2
)
O(N^2 \times M^2)
O(N2×M2) 的算法,所以根本不需要什么二分答案。
对于
1
≤
N
,
M
≤
300
1 \leq N,M \leq 300
1≤N,M≤300,直接考虑暴力枚举,首先假设不删除任何比赛,此时就必定有一个参加人数最多的项目,那么就删除这个项目。
重复这个过程即可,最多删除
M
−
1
M-1
M−1 次。
AC Code
#include<bits/stdc++.h>
#define arrout(a,n) rep(i,1,n)std::cout<<a[i]<<" "
#define arrin(a,n) rep(i,1,n)std::cin>>a[i]
#define rep(i,x,n) for(int i=x;i<=n;i++)
#define dep(i,x,n) for(int i=x;i>=n;i--)
#define erg(i,x) for(int i=head[x];i;i=e[i].nex)
#define dbg(x) std::cout<<#x<<":"<<x<<" "
#define mem(a,x) memset(a,x,sizeof a)
#define all(x) x.begin(),x.end()
#define arrall(a,n) a+1,a+1+n
#define PII std::pair<int,int>
#define m_p std::make_pair
#define u_b upper_bound
#define l_b lower_bound
#define p_b push_back
#define CD const double
#define CI const int
#define int long long
#define il inline
#define ss second
#define ff first
#define itn int
CI N=305;
int n,m,ans=LLONG_MAX,a[N][N],b[N],vis[N];
signed main() {
std::cin>>n>>m;
rep(i,1,n) {
rep(j,1,m) {
std::cin>>a[i][j];
}
}
int t=m;
while(t--) {
mem(b,0);
rep(i,1,n) {
rep(j,1,m) {
if(!vis[a[i][j]]) {//记录第i个选手参加哪一场比赛
b[a[i][j]]++;
break;
}
}
}
int max=0,idx=0;//max: 人数最多的比赛的人数, idx: 人数最多的比赛的编号
rep(j,1,m) {
if(max<b[j]) {
max=b[j];
idx=j;
}
}
ans=std::min(ans,max);
vis[idx]=1;//删除这个比赛
}
std::cout<<ans;
return 0;
}