我是靠谱客的博主 健壮飞机,最近开发中收集的这篇文章主要介绍2020ICPC沈阳 - United in Stormwind(推公式+FWT+SOSdp),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

题目链接:点击查看

题目大意:规定一张试卷上有 m m m 个问题,每个问题只有 A , B A,B A,B 两个选项,现在给出 n n n 张试卷。需要选择一个问题的子集,使得有大于等于 k k k 对试卷的答案是不完全相同的,问这样的子集有多少个

题目分析:若将选项转换为 0 0 0 1 1 1,试卷视为 01 01 01 串,那么两个试卷相同,当且仅当异或和等于 0 0 0

a i a_i ai 为第 i i i 个试卷所代表的 01 01 01 串, F ( S ) F(S) F(S) 为异或和等于 S S S 01 01 01 串对的个数,则

F ( S ) = ∑ i = 1 n ∑ j = i n [ a i ⊕ a j = S ] F(S)=sumlimits_{i=1}^{n}sumlimits_{j=i}^{n}{[a_ioplus a_j=S]} F(S)=i=1nj=in[aiaj=S]

不难发现可以转换为卷积的形式,设 n u m [ x ] num[x] num[x] x x x 的出现次数,则

F ( S ) = 1 2 ∑ i ⊕ j = S n u m [ i ] ∗ n u m [ j ] F(S)=frac{1}{2}sumlimits_{ioplus j=S}num[i]*num[j] F(S)=21ij=Snum[i]num[j]

G ( T ) G(T) G(T) 为问题集合为 T T T 时,有多少对试卷是不相同的,则

G ( T ) = ∑ T ∩ S ≠ ∅ F ( S ) G(T)=sumlimits_{Tcap Sneq varnothing}F(S) G(T)=TS=F(S)

容斥一下

G ( T ) = n 2 2 − ∑ T ∩ S = ∅ F ( S ) = n 2 2 − ∑ S ⊂ ( U − T ) F ( S ) G(T)=frac{n^2}{2}-sumlimits_{Tcap S= varnothing}F(S)=frac{n^2}{2}-sumlimits_{Ssubset (U-T)}F(S) G(T)=2n2TS=F(S)=2n2S(UT)F(S)

可能有些同学会有疑问,为什么这里突然出来一个 n 2 2 frac{n^2}{2} 2n2,因为根据 F ( S ) F(S) F(S) 的定义, F ( S ) F(S) F(S) 的最大值是这个数,所以设置为 F F F 函数的“全集”。

然后 U U U 是全集, U − T U-T UT 自然也就是 T T T 的补集。

到此公式就推完了, F ( S ) F(S) F(S) 可以用 F W T FWT FWT 快速求解, G ( T ) G(T) G(T) 可以用 S O S d p SOSdp SOSdp 快速求解

代码:

// Problem: United in Stormwind
// Contest: NowCoder
// URL: https://ac.nowcoder.com/acm/contest/18713/M
// Memory Limit: 2097152 MB
// Time Limit: 4000 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=5e6+100;
char s[N];
double F[N];
LL G[N];
void FWTxor(double *f,double x,int len)
{
	for(int mid=1;(mid<<1)<=len;mid<<=1)
	{
		int R=mid<<1;
		for(int i=0;i<len;i+=R)
			for(int j=0;j<mid;j++)
			{
				f[i+j]=f[i+j]+f[i+j+mid];
				f[i+j+mid]=f[i+j]-f[i+j+mid]-f[i+j+mid];
				f[i+j]=f[i+j]*x;
				f[i+j+mid]=f[i+j+mid]*x;
			}
	}
}
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;
	LL k;
	read(n),read(m),read(k);
	for(int i=1;i<=n;i++) {
		scanf("%s",s);
		int state=0;
		for(int j=0;j<m;j++) {
			if(s[j]=='A') {
				state|=(1<<j);
			}
		}
		F[state]+=1.0;
	}
	FWTxor(F,1,1<<m);
	for(int i=0;i<1<<m;i++) {
		F[i]*=F[i];
	}
	FWTxor(F,0.5,1<<m);
	for(int i=0;i<1<<m;i++) {
		G[i]=LL(F[i]/2);
	}
	for(int j=0;j<m;j++) {
		for(int i=0;i<1<<m;i++) {
			if(i>>j&1) {
				G[i]+=G[i^(1<<j)];
			}
		}
	}
	int ans=0;
	for(int i=0;i<1<<m;i++) {
		if(1LL*n*n-G[i]*2>=k*2) {
			ans++;
		}
	}
	cout<<ans<<endl;
	return 0;
}

最后

以上就是健壮飞机为你收集整理的2020ICPC沈阳 - United in Stormwind(推公式+FWT+SOSdp)的全部内容,希望文章能够帮你解决2020ICPC沈阳 - United in Stormwind(推公式+FWT+SOSdp)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(27)

评论列表共有 0 条评论

立即
投稿
返回
顶部