洛谷
题解
]
P12788 [ICPC 2024 Yokohama R] Scheduling 题解
题意:给定 $n$ 个二进制数 $a_i$,你要从中选出一个二元组 $(a_x,a_y)$,要求 $a_x\wedge a_y=2^m-1$。若存在多解,则最大化 $\operatorname{pop}(a_x\vee a_y)$;若仍存在多解,则最小化 $x$,若仍存在多解,则最小化 $y$。若无解则输出 NO
。
千万别读错题,一开始没注意到要求 $a_x\wedge a_y=2^m-1$,以为是最大化 $a_x\wedge a_y$,想了好久呜呜呜。
不妨考虑枚举 $x$,选取最优的 $y$。
首先,$a_x\wedge a_y=2^m-1$,所以 $y$ 是 $2^m-1-a_x$(即 $\neg a_x$)的超集。
我们知道 $\operatorname{pop}(a_x\vee a_y)=\operatorname{pop}(a_x)+\operatorname{pop}(a_y)-\operatorname{pop}(a_x\wedge a_y)$。由于 $a_x\wedge a_y=2^m-1$,因此 $\operatorname{pop}(a_x\wedge a_y)=m$。
$\operatorname{pop}(a_x\vee a_y)=\operatorname{pop}(a_x)+\operatorname{pop}(a_y)-m$,如果固定 $\operatorname{pop}(a_x)$,那么 $\operatorname{pop}(a_y)$ 越大越好。
至于 $x,y$ 最小的限制,只需在 $\neg a_x$ 的超集中选取 $\operatorname{pop}(a_y)$ 时使 $y$ 尽可能小即可。
这个东西可以预处理,即对于每个数 $k\in[0,2^m-1]$ 开个 pair
,first
是 $\operatorname{pop}(a_y)$,second
是 $y$,并且 $a_y$ 是 $k$ 的超集。
由于 first
越大越好,second
越小越好,所以为了写代码方便,second
存的是负数。这样预处理就是做个高维后缀 $\max$。
注意以下特殊数据,你的代码很有可能会在这些地方 WA:
- 存在 $a_i=2^m-1$;
- 所有 $a_i=2^m-1$ 或 $a_i=0$。
建议赋初值为 $-\inf$ 减少特判。
#include<bits/stdc++.h>
#define siz(x) int((x).size())
#define all(x) std::begin(x),std::end(x)
#define fi first
#define se second
#define popcnt __builtin_popcount
using namespace std;
using unt=unsigned;
using loli=long long;
using lolu=unsigned long long;
using pii=pair<int,int>;
mt19937_64 rng(random_device{}());
constexpr int N=2e5+7,M=21,inf=0x3f3f3f3f;
int n,m,a[N],sum=-inf;
pii f[1<<M],ans;
signed main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
ios::sync_with_stdio(false);cin.tie(nullptr);
cin>>n>>m;
for(int i=(1<<m)-1;i;i--)
f[i]={-inf,-inf};
for(int i=1;i<=n;i++){
string s;cin>>s;
for(int j=0;j<m;j++)if(s[j]=='Y')
a[i]|=(1<<j);
f[a[i]].fi=popcnt(a[i]);
if(f[a[i]].se==-inf)f[a[i]].se=-i;
}
for(int i=(1<<m)-1;i;i--)for(int j=0;j<m;j++)
if(i>>j&1)f[i^(1<<j)]=max(f[i^(1<<j)],f[i]);
for(int i=1;i<=n;i++){
auto tmp=f[(1<<m)-1-a[i]];
if(-tmp.se==i)continue;
auto cnt=popcnt(a[i])+tmp.fi-(m-popcnt(a[i]));
if(sum<cnt||(sum==cnt&&ans>pii(minmax(i,-tmp.se)))){
sum=cnt;
ans=pii(minmax(i,-tmp.se));
}
}
if(sum<0)cout<<"No\n";
else cout<<ans.fi<<' '<<ans.se<<'\n';
return 0;
}