[二分图] [状压] [SOSdp] [ARC106E] Medals
首先二分答案,暴力拆点跑二分图最大匹配,不行会超时,需要优化。
尝试使用
注意到一个重要性质:我们依次给每个人颁奖,那么总天数为
这启示我们从奖牌出发考虑贡献,记
但是这并不好计算,不妨换个角度,计算
注意二分前预处理
代码
#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
const int N = 25, M = 4e6 + 5, MX = 1 << 18;
int n, k, a[N], P[M], f[MX], ppc[MX];
inline bool check(int p){
for(int i = 0; i < MX; ++i) f[i] = 0;
for(int i = 1; i <= p; ++i) ++f[P[i]];
for(int i = 0; i < n; ++i)
for(int S = 0; S < 1 << n; ++S)
if((S >> i) & 1) f[S] += f[S ^ (1 << i)];
for(int S = 1; S < 1 << n; ++S){
int res = p - f[((1 << n) - 1) ^ S];
if(ppc[S] * k > res) return false;
}
return true;
}
signed main(){
for(int i = 1; i < MX; ++i) ppc[i] = ppc[i ^ (i & -i)] + 1;
cin >> n >> k;
for(int i = 0; i < n; ++i) scanf("%d", &a[i]);
for(int i = 1; i <= 2 * n * k; ++i)
for(int j = 0; j < n; ++j){
int id = i % (2 * a[j]);
if(id && id <= a[j]) P[i] |= (1 << j);
}
int L = 0, R = 2 * n * k;
while(L + 1 < R){
int mid = L + R >> 1;
if(check(mid)) R = mid;
else L = mid;
}
cout << R;
return 0;
}