传送门
文章目录
- 题意:
- 思路:
题意:
有nnn个试卷,每个试卷有mmm个问题,每个问题有两个选项a,ba,ba,b,定义两个试卷不同当且仅当其选中的问题中有一个问题不同。现在问你对于mmm个问题的所有子集,有多少个子集问题不同的对数≥k\ge k≥k个。
1≤n≤2e5,1≤m≤20,1≤k≤n∗(n−1)21\le n\le2e5,1\le m\le20,1\le k\le\frac{n*(n-1)}{2}1≤n≤2e5,1≤m≤20,1≤k≤2n∗(n−1)
思路:
我们将不同选项看成010101串,两个集合不完全相同的话他们的异或肯定不为000,对于我们已经选中的子集SSS来说,他的答案为F(S)=∑i=1n∑j=i+1n[ansi⊕ansj>0]F(S)=\sum_{i=1}^n\sum_{j=i+1}^n[ans_i\oplus ans_j>0]F(S)=∑i=1n∑j=i+1n[ansi⊕ansj>0]。
考虑将这个式子转换一下,设cnt[i]cnt[i]cnt[i]代表iii这个二进制出现了几次,F(S)=12∗∑i⊕j=Scnt[i]∗cnt[j]F(S)=\frac{1}{2}*\sum_{i\oplus j=S}cnt[i]*cnt[j]F(S)=21∗∑i⊕j=Scnt[i]∗cnt[j],这个显然可以fwtfwtfwt处理出来。
那么考虑SSS对于哪些子集有贡献,举个例子,比如子集是110110110,那么他有贡献的子集集合是100,110,101,010,011,111100,110,101,010,011,111100,110,101,010,011,111,一开始没注意到101,011101,011101,011这两个集合,以为直接sosdpsosdpsosdp求一遍超集一遍子集就有了,显然是不可以的。
正着来不好弄,我们考虑将其容斥一下。
对于110110110,显然他没有贡献到的集合就是001001001的超集,也就是其补集的超集,所以我们做一个容斥,记G[S]G[S]G[S]表示SSS集合中对应答案相同的点对数量,这个可以用sosdpsosdpsosdp求出来超集,答案即为∑i=0(1<<m)−1[n∗(n−1)2−G[i]>=k]\sum_{i=0}^{(1<<m)-1}[\frac{n*(n-1)}{2}-G[i]>=k]∑i=0(1<<m)−1[2n∗(n−1)−G[i]>=k]。
// 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("Ofast,no-stack-protector,unroll-loops,fast-math")
//#pragma GCC target("sse,sse2,sse3,ssse3,sse4.1,sse4.2,avx,avx2,popcnt,tune=native")
//#pragma GCC optimize(2)
#include<cstdio>
#include<iostream>
#include<string>
#include<cstring>
#include<map>
#include<cmath>
#include<cctype>
#include<vector>
#include<set>
#include<queue>
#include<algorithm>
#include<sstream>
#include<ctime>
#include<cstdlib>
#include<random>
#include<cassert>
#define pb push_back
#define mk make_pair
#define Mid ((tr[u].l+tr[u].r)>>1)
#define Len(u) (tr[u].r-tr[u].l+1)
#define random(a,b) ((a)+rand()%((b)-(a)+1))
#define db puts("---")
using namespace std;//void rd_cre() { freopen("d://dp//data.txt","w",stdout); srand(time(NULL)); }
void rd_ac() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//AC.txt","w",stdout); }
//void rd_wa() { freopen("d://dp//data.txt","r",stdin); freopen("d://dp//WA.txt","w",stdout); }typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;const int N=10000010,mod=1e9+7,INF=0x3f3f3f3f;
const double eps=1e-6;int n,m;
LL a[N],k;
LL f[N],g[N];
char s[N];void FWT_xor(LL *a,int opt,int N)
{for(int i=1;i<N;i<<=1)for(int p=i<<1,j=0;j<N;j+=p)for(int k=0;k<i;++k){LL X=a[j+k],Y=a[i+j+k];a[j+k]=(X+Y);a[i+j+k]=(X-Y);if(opt==-1)a[j+k]=1ll*a[j+k]/2,a[i+j+k]=1ll*a[i+j+k]/2;}
}int main()
{
// ios::sync_with_stdio(false);
// cin.tie(0);cin>>n>>m>>k;for(int i=1;i<=n;i++) {scanf("%s",s);int now=0;for(int j=0;s[j];j++) {if(s[j]=='B') now+=1<<j;}a[now]++;}FWT_xor(a,1,1<<m);for(int i=0;i<1<<m;i++) a[i]=a[i]*a[i];FWT_xor(a,-1,1<<m);a[0]-=n;for(int i=0;i<1<<m;i++) g[i^((1<<m)-1)]=a[i]/2;for(int i=0;i<m;i++) {for(int j=0;j<1<<m;j++) {if(j>>i&1) g[j^(1<<i)]+=g[j];}}int ans=0;for(int i=1;i<1<<m;i++) {LL now=1ll*n*(n-1)-g[i]*2;if(now>=k*2) ans++;}cout<<ans<<endl;return 0;
}
/*110 -> 001
001 -> 110
111 -> 000010
101
011110 +1 -> 100 010 111 101 011 -> 100 110 101 111 | 010 110 011 111
001 +1
111 +1100 +1 +1
010 +1 +1
001 +1 +1
110 +1
101 +1 +1 +1
011 +1 +1 +1
111 +1 +1 +1*/