概述
题目链接:点击查看
题目大意:规定一张试卷上有 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=1∑nj=i∑n[ai⊕aj=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)=21i⊕j=S∑num[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)=T∩S=∅∑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)=2n2−T∩S=∅∑F(S)=2n2−S⊂(U−T)∑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 U−T 自然也就是 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)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复