https://codeforces.com/contest/1484/problem/C
思路:
昨晚贪心了5次都是wa。
原本思路:处理当前每个数已经拿了几次,还能拿几次。
代码细节问题:一层扫完后再更新。
中午上课讨论了一下发现有一个hack
3 6
3 1 2 3
3 1 2 3
3 1 2 3
1 1
1 1
1 1
原因在于后面只能拿1导致均分不对了。
于是我们先处理1天的。更新每个数的已经拿的状态和还能拿的状态,然后回到上面的均分,每一次层拿当前已经拿的人数中最少的。如果一样看后面哪个不多拿哪个。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=1e5+1000;
typedef long long LL;
inline LL read(){LL x=0,f=1;char ch=getchar(); while (!isdigit(ch)){if (ch=='-') f=-1;ch=getchar();}while (isdigit(ch)){x=x*10+ch-48;ch=getchar();}
return x*f;}
map<LL,LL>map1;///前面的
map<LL,LL>map2;///后面的
map<LL,LL>map3;///check
vector<LL>g[maxn];
vector<LL>v[maxn];
int main(void)
{
cin.tie(0);std::ios::sync_with_stdio(false);
LL t;cin>>t;
while(t--){
map1.clear();
map2.clear();
map3.clear();
LL n,m;cin>>n>>m;
for(LL i=0;i<m+10;i++) g[i].clear(),v[i].clear();
for(LL i=1;i<=m;i++){
LL k;cin>>k;
for(LL j=1;j<=k;j++){
LL x;cin>>x;
g[i].push_back(x);
map2[x]++;
}
}
///先处理一天的
for(LL i=1;i<=m;i++){
LL k=g[i].size();
if(k==1){
map1[g[i][0]]++;
map2[g[i][0]]--;
v[i].push_back(g[i][0]);
}
}
for(LL i=1;i<=m;i++){
LL num=0;LL cnt=0x3f3f3f3f;
if(g[i].size()==1) continue;
for(auto j:g[i]){
if(cnt>map1[j]){
cnt=map1[j];
num=j;
}
else if(cnt==map1[j]){
if(map2[num]>map2[j]){
num=j;
}
}
///扫完再加减
}
v[i].push_back(num);
map1[num]++;
for(auto j:g[i]){
map2[j]--;
}
}
for(LL i=1;i<=m;i++){
for(auto j:v[i]){
map3[j]++;
}
}
LL num=(m+1)/2;
bool flag=1;
for(auto i:map3){
if(i.second>num){
flag=0;
break;
}
}
if(flag==0){
cout<<"NO"<<"\n";
}
else{
cout<<"YES"<<"\n";
for(LL i=1;i<=m;i++){
cout<<v[i][0]<<" ";
}
cout<<"\n";
}
}
return 0;
}