题目大意
有n个人,第i个人有一个ai,表示其第[k(2ai)+1,k(2ai)+ai]天在
每天可以给至多一个人发一枚奖牌,求所有人都发了只少K枚奖牌的最小时间
n<=18,K,ai<=1e5
题解
如果能想到hall定理的话就没了
一个人拆成K个点,二分答案,暴力加边,hall定理判断,要预处理选牌的人的集合
code
#include <bits/stdc++.h>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define low(x) ((x)&-(x))
#define ll long long
//#define file
using namespace std;
int a[19],b[4000001],f[262144],p[19],num[262144],n,K,i,j,k,l,L,R,Mid;
void init()
{
int s,i,j,k,l;
p[0]=1;
fo(i,1,n) p[i]=p[i-1]*2;
fo(i,1,p[n]-1) num[i]=num[i-low(i)]+1;
fo(i,1,4000000)
{
s=0;
fo(j,1,n)
if ((i-1)%(a[j]*2)<a[j])
s+=p[j-1];
b[i]=s;
}
}
bool pd(int t)
{
int i,j,k,l,s;
memset(f,0,sizeof(f));
fo(i,1,t) ++f[p[n]-1],--f[b[i]^(p[n]-1)];
fo(i,1,n)
{
fo(j,0,p[n]-1)
if (j&p[i-1])
f[j-p[i-1]]+=f[j];
}
fo(i,0,p[n]-1)
if (num[i]*K>f[i])
return 0;
return 1;
}
int main()
{
#ifdef file
freopen("e.in","r",stdin);
#endif
scanf("%d%d",&n,&K);
fo(i,1,n) scanf("%d",&a[i]);
init();
L=1,R=4000000;
while (L<R)
{
Mid=(L+R)/2;
if (!pd(Mid))
L=Mid+1; else R=Mid;
}
printf("%d
",L);
fclose(stdin);
fclose(stdout);
return 0;
}