首页 > 其他 > 详细

CF 1523D - Love-Hate

时间:2021-05-31 21:54:51      阅读:30      评论:0      收藏:0      [点我收藏+]
  • 考虑枚举每个人,选择它的集合的子集作为方案。

    这样只有本质不同的 \(2^p\) 个集合,枚举子集或者 FMT 每次可以做到 \(O(3^p/p2^p)\)

  • 但是人太多了怎么办?注意到每个人都有 \(\frac {1}{2}\) 的概率出现在方案中,连续 \(k\) 个人都不在方案中的概率为 \({\frac{1}{2}}^k\)

    那么将顺序打乱,只用选 \(40\) 个人就可以取得非常高的正确率。

#include <bits/stdc++.h>
using namespace std;

typedef long long LL;

const int N = 2e5 + 10;

int n, mx, m, a[64], b[1<<15], c[1<<15], tot;

LL ans, v[N];

char s[N];

void check_(LL x) {
	tot = 0;
	
	for (int i = 0; i < m; i++)	
		if (x&(1ll<<i))
			a[tot++] = i;
	
	for (int i = 0; i < (1<<tot); i++)	
		b[i] = 0, c[i] = c[i>>1] + (i&1);
			
	for (int i = 1; i <= n; i++) {
		int cur = 0;
		
		for (int j = 0; j < tot; j++)
			if (v[i]&(1ll<<a[j]))
				cur += 1<<j;
		
		b[cur]++;
	}
	
	for (int i = 0; i < tot; i++)
		for (int j = 0; j < (1<<tot); j += 2ll<<i)
			for (int k = 0; k < (1<<i); k++)
				b[j + k] += b[j + k + (1<<i)];
	
	for (int i = (1<<tot) - 1; i; i--)
		if (b[i]*2 >= n && c[i] > mx) {
			mx = c[i], ans = 0;
			
			for (int j = 0; j < tot; j++)
				if (i&(1<<j))	
					ans |= 1ll<<a[j];
		}
}

int main() {
	srand(time(0));
	
	scanf("%d%d%*d", &n, &m);
	
	for (int i = 1; i <= n; i++) {
		scanf("%s", s);
		
		for (int j = 0; j < m; j++)
			if (s[j] == ‘1‘)
				v[i] |= 1ll<<j;
	}
	
	random_shuffle(v + 1, v + n + 1);
	
	for (int i = 1; i <= min(32, n); i++)
		check_(v[i]);
	
	for (int i = 0; i < m; i++)
		printf("%d", (ans&(1ll<<i)) > 0);
} 

CF 1523D - Love-Hate

原文:https://www.cnblogs.com/iqx37f/p/14833020.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!