标签:tmp Love int Codeforces 50 随机化 集合 物品 dp
题目大意
有\(n\)个人,\(m\)个物品,每个人最多喜欢\(p\)个物品,要你选一个物品的集合,这个集合中的所有物品都被不少于\(\lfloor \frac{n}{2} \rfloor\)的人喜欢。
解题思路
很有意思的一道题,通过这个题学习了SOS dp和随机化算法。首先我们选50个人出来,这50个人中所有人喜欢的物品的子集都不是最优解的可能性是\(\frac{1}{2^{50}}\),概率十分的低,所以我们大可以认为选出的50个人中的一个子集必定是最优解。
然后就是怎么求最优解了,我们可以枚举每个人喜欢物品的集合的子集\(s\),如果\(n\)个集合中\(s\)的超集不少于\(\lfloor \frac{n}{2} \rfloor\)个,那么这个子集就是解中的一个。怎么求超集呢?这就用到sos dp了。首先把抽出来的这个人所有喜欢的物品拉出来当作一个集合,然后再统计出所有人喜欢的物品与这个集合的交集,然后用sos dp求出来所有交集的超集就行了。
代码
const int maxn = 2e5+10;
const int maxm = 2e6+10;
ll arr[maxn], dp[maxn];
int main() {
IOS;
srand(time(0));
int n, m, p; cin >> n >> m >> p;
for (int i = 1; i<=n; ++i) {
string s; cin >> s;
for (int j = 0; j<m; ++j) arr[i] |= ((1LL*(s[j]=='1'))<<j);
}
int ans = 0;
string s(m, '0');
for (int i = 1; i<=50; ++i) {
int p = 1LL*rand()*rand()%n+1;
vector<int> tmp;
for (int j = 0; j<m; ++j)
if (arr[p]>>j&1) tmp.push_back(j);
clr(dp, 0);
int sz = tmp.size();
for (int j = 1; j<=n; ++j) {
int t = 0;
for (int k = 0; k<sz; ++k)
if ((1LL<<tmp[k])&arr[j]) t ^= (1<<k);
++dp[t];
}
for (int j = 0; j<sz; ++j)
for (int k = 0; k<(1<<sz); ++k)
if (k>>j&1) dp[k^(1<<j)] += dp[k];
for (int j = 0; j<(1<<sz); ++j) {
if (dp[j]*2<n) continue;
int x = __builtin_popcount(j);
if (x>ans) {
ans = x;
s.clear();
for (int k = 0; k<m; ++k) s += '0';
for (int k = 0; k<sz; ++k)
if (j>>k&1) s[tmp[k]] = '1';
}
}
}
cout << s << endl;
return 0;
}
标签:tmp,Love,int,Codeforces,50,随机化,集合,物品,dp 来源: https://www.cnblogs.com/shuitiangong/p/15257684.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。