CodeForces - 1523D Love-Hate(随机数+状压dp)

Posted Frozen_Guardian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了CodeForces - 1523D Love-Hate(随机数+状压dp)相关的知识,希望对你有一定的参考价值。

题目链接:点击查看

题目大意:给出 n n n 01 01 01 序列表示二进制状态,问选择至少 ⌈ n 2 ⌉ \\lceil \\frac{n}{2}\\rceil 2n 个状态进行位运算的与运算后得到的答案中, 1 1 1 的位数最多的答案

题目分析:考虑最后需要求得的答案,一定是 ⌈ n 2 ⌉ \\lceil \\frac{n}{2}\\rceil 2n 个状态中,其中一个状态的子集,于是我们就可以去枚举然后统计答案

考虑随机数,每随机抽一个状态,不在最后 ⌈ n 2 ⌉ \\lceil \\frac{n}{2}\\rceil 2n 个数的概率为 1 2 \\frac{1}{2} 21,我们可以抽 50 50 50 次甚至更多,抽不中的概率就是 ( 1 2 ) 50 (\\frac{1}{2})^{50} (21)50,这个概率以及近似无限接近百分百了

现在的问题就转换为了,给定一个状态,如何快速枚举其子集并统计其出现的个数

最朴素的做法就是,对于每个状态状压枚举其子集,然后维护一个 c n t cnt cnt 数组计数,这个复杂度是 O ( n ∗ 2 p ) O(n*2^p) O(n2p)

所以考虑用状压 d p dp dp 去维护前缀和的思想,假设现在有两个状态 i , j i,j i,j,满足 i i i j j j 的一个子集,即 i & j = j i\\&j=j i&j=j,则根据前缀和的思想,可以有 c n t j + = c n t i cnt_j+=cnt_i cntj+=cnti

利用以上的优化,我们可以 O ( n p ) O(np) O(np) 处理出初始的 c n t cnt cnt 数组,然后 O ( p ∗ 2 p ) O(p*2^p) O(p2p) 状压 d p dp dp 维护一下前缀和就好了

剩下的 O ( p ∗ 2 p ) O(p*2^p) O(p2p) 再枚举一下答案更新就可以了

代码:

// Problem: D. Love-Hate
// Contest: Codeforces - Deltix Round, Spring 2021 (open for everyone, rated, Div. 1 + Div. 2)
// URL: https://codeforces.com/contest/1523/problem/D
// Memory Limit: 256 MB
// Time Limit: 3000 ms
// 
// Powered by CP Editor (https://cpeditor.org)

// #pragma GCC optimize(2)
// #pragma GCC optimize("Ofast","inline","-ffast-math")
// #pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<list>
#include<unordered_map>
#define lowbit(x) x&-x
using namespace std;
typedef long long LL;
typedef unsigned long long ull;
template<typename T>
inline void read(T &x)
{
	T f=1;x=0;
	char ch=getchar();
	while(0==isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
	while(0!=isdigit(ch)) x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
	x*=f;
}
template<typename T>
inline void write(T x)
{
	if(x<0){x=~(x-1);putchar('-');}
    if(x>9)write(x/10);
    putchar(x%10+'0');
}
const int inf=0x3f3f3f3f;
const int N=1e6+100;
mt19937_64 eng(time(NULL));
LL s[N];
int cnt[(1<<15)+100];
int a[N];
int main()
{
#ifndef ONLINE_JUDGE
//	freopen("data.in.txt","r",stdin);
//	freopen("data.out.txt","w",stdout);
#endif
//	ios::sync_with_stdio(false);
	int n,m,p;
	read(n),read(m),read(p);
	for(int i=1;i<=n;i++) {
		string str;
		cin>>str;
		for(int j=0;j<m;j++) {
			if(str[j]=='1') {
				s[i]|=(1LL<<j);
			}
		}
	}
	iota(a+1,a+1+n,1);
	shuffle(a+1,a+1+n,eng);
	int ans=-1;
	string res;
	for(int t=1;t<=min(50,n);t++) {
		memset(cnt,0,sizeof(cnt));
		int p=a[t];
		vector<int>bits;
		for(int j=0;j<m;j++) {
			if((s[p]>>j)&1) {
				bits.push_back(j);
			}
		}
		int sz=bits.size();
		for(int i=1;i<=n;i++) {//n*p
			int state=0;
			for(int j=0;j<sz;j++) {
				if((s[i]>>bits[j])&1) {
					state|=(1<<j);
				}
			}
			cnt[state]++;
		}
		for(int j=0;j<sz;j++) {//p*2^p
			for(int i=0;i<1<<sz;i++) {
				if(((i>>j)&1)==0) {
					cnt[i]+=cnt[i|(1<<j)];
				}
			}
		}
		for(int i=0;i<1<<sz;i++) {
			if(cnt[i]>=(n+1)/2&&__builtin_popcount(i)>ans) {
				ans=__builtin_popcount(i);
				res=string(m,'0');
				for(int j=0;j<sz;j++) {
					if((i>>j)&1) {
						res[bits[j]]='1';
					}
				}
			}
		}
	}
	cout<<res<<endl;
	return 0;
}

以上是关于CodeForces - 1523D Love-Hate(随机数+状压dp)的主要内容,如果未能解决你的问题,请参考以下文章

如何看codeforces做了多少题

codeforces上怎么看测试数据

codeforces比赛后怎么看题解和答案

codeforces是啥?

codeforces Codeforces 650A Watchmen

CodeForces - 504A && CodeForces - 624C && CodeForces - 2B