AtCoder GC 018B: Sports Festival 题解

来源:互联网 发布:linux渗透测试系统 编辑:程序博客网 时间:2024/05/16 15:01

首先显然的是二分答案

设二分出的答案为mid

然后就要验证解是否可行

可以这样验证:现将所有运动员按照第一志愿扔进vector

然后贪心的删除项目:每次找选择人数最多的项目,如果这个项目的人数超过mid,那么如果这个项目不删除,这个项目的人数一定不会变少,也就不可能完成mid的要求

所以将这个项目删除,然后给选择这个项目的所有运动员按照志愿重新安排项目(存在的),如果删光了所有的项目,就无法完成,如果某一时刻选择人数最多的项目人数<=mid,就可行

总复杂度O(n*n*logn)

#include <cstdio>#include <iostream>#include <cstring>#include <string>#include <cmath>#include <algorithm>#include <cstdlib>#include <utility>#include <map>#include <stack>#include <set>#include <vector>#include <queue>#include <deque>#define x first#define y second#define mp make_pair#define pb push_back#define LL long long#define Pair pair<int,int>#define LOWBIT(x) x & (-x)using namespace std; const int MOD=1e9+7;const int INF=1e9;const int magic=348; int n,m;int a[348][348];vector<int> v[348];priority_queue<Pair> q;int cur[348];bool used[348]; bool check(int cmp){if (cmp==n) return true;int i,j;for (i=1;i<=n;i++) cur[i]=1;for (i=1;i<=m;i++) v[i].clear();for (i=1;i<=n;i++) v[a[i][1]].pb(i);//for (i=1;i<=m;i++) cout<<v[i].size()<<' ';//cout<<endl;for (i=1;i<=m;i++) used[i]=true;for (i=1;i<=m;i++){int maxn=-1,max_pos;for (j=1;j<=m;j++){int len=v[j].size();//cout<<j<<' '<<v[j].size()<<' '<<maxn<<' '<<used[j]<<endl;if (used[j]==true && len>maxn){//cout<<"#";//cout<<j<<' '<<v[j].size()<<endl;maxn=v[j].size();max_pos=j;}}if (maxn<=cmp) return true;if (i==m) return false;used[max_pos]=false;for (j=0;j<v[max_pos].size();j++){int x=v[max_pos][j];cur[x]++;while (!used[a[x][cur[x]]]) cur[x]++;v[a[x][cur[x]]].pb(x);}}return false;} int main (){int i,j;scanf("%d%d",&n,&m);for (i=1;i<=n;i++)for (j=1;j<=m;j++)scanf("%d",&a[i][j]);int l=1,r=n,mid,ans;while (l<=r){mid=(l+r)>>1;if (check(mid)){ans=mid;r=mid-1;}elsel=mid+1;}printf("%d\n",ans);return 0;}


原创粉丝点击