[图论记录]ARC106E Medals

command_block

2021-10-26 10:51:37

Personal

**题意** : 你经营一家雇用 $n$ 名员工的商店。每个员工都有固定的工作周期。 具体地,从今天开始,第 $i$ 位员工重复以下内容:干 $A_i$ 天活,休息 $A_i$ 天。 从今天开始的每一天,你可以选择的当天上班的员工之一,颁发一枚奖章。(如果没有员工上班,那天你什么也不做。) 给每位员工颁发至少 $k$ 枚奖牌至少需要多少天? $n\leq 18,k,A\leq 10^5$ ,时限$\texttt{3s}$。 ------------ 毛估估一下答案上界大概是 $nk$ 级别的,开个 $6nk$ 感觉非常稳。 建模:一个二分图,左部是员工,共 $n$ 个点;右部是日子,有无穷多个。若某个员工在某个日子上班,则连边。 问题相当于求至少保留多少个日子,才能使得二分图有完美匹配。 考虑二分,并使用(多重扩展) Hall 定理。 只需算出每个左部点(员工)集合的邻域大小 $H_S$。 记 $E_i$ 为第 $i$ 天的边集,则 $H_S=\sum\limits_{i}[E_i\cap S\neq \varnothing]=\sum\limits_{i}1-[\neg E_i\supseteq S]$。 可以高维后缀和(超集和)计算。 ```cpp #include<algorithm> #include<cstdio> #define MaxN 100500 #define MaxS 270000 using namespace std; const int INF=1000000000; int n,k,cnt[MaxS],o[MaxS],s[11000000]; bool chk(int lim) { for (int i=0;i<(1<<n);i++)o[i]=0; for (int t=0;t<lim;t++)o[s[t]]++; for (int len=1;len<(1<<n);len<<=1) for (int p=0;p<(1<<n);p+=len+len) for (int k=0;k<len;k++) o[p|k]+=o[p|k|len]; for (int i=1;i<(1<<n);i++) if (cnt[i]*k>lim-o[i])return 0; return 1; } int a[20]; int main() { scanf("%d%d",&n,&k); for (int i=1;i<(1<<n);i++) cnt[i]=cnt[i>>1]+(i&1); for (int i=0,a;i<n;i++){ scanf("%d",&a); for (int j=0;j<6*n*k;j+=a+a) for (int t=j+a;t<j+a+a;t++) s[t]|=(1<<i); } int l=0,r=6*n*k,mid; while(l<r){ mid=(l+r)>>1; if (chk(mid))r=mid; else l=mid+1; }printf("%d",r); return 0; } ```