[容斥][组合数][暴力]JZOJ 3295 【SDOI2013】泉
分析
题意为在n个六元组中求出有多少对满足刚好k个对应位置的量相等
k很小,我们可以枚举所有2^6种状况
我们发现刚好有k种的情况比较难做,不如考虑至少k种的
设至少k种的情况为f[k]
那么ans=f[k]-f[k+1]*C(k+1,k)+f[k+2]*C(k+2,k)-f[k+3]*C(k+3,k)+……
k+x<=6
为什么要乘上C(k+x,k)呢?我们可以发现每个刚好为k+x的情况都可以对答案产生C(k+x,k)的贡献
#include <iostream> #include <cstdio> #include <memory.h> using namespace std; typedef unsigned long long ull; typedef long long ll; const int N=1e5+10; const int P=17453343; const int Typi=133345; struct List { ull v; int nx,cnt; }l[N]; int cnt,list[P]; int n,k; int a[N][7]; ll ans,C[7][7]; void Insert(ull x) { int u=x%P; for (int i=list[u];i;i=l[i].nx) if (l[i].v==x) { l[i].cnt++; return; } l[++cnt]=(List){x,list[u],1};list[u]=cnt; } void Calc(int m) { int rnt=0; for (int i=0;i<6;i++) if (m&(1<<i)) rnt++; if (rnt<k) return; memset(list,0,sizeof list);cnt=0; for (int i=1;i<=n;i++) { ull hash=0; for (int j=0;j<6;j++) if (m&(1<<j)) hash=hash*Typi+a[i][j]; Insert(hash); } ll count=0; for (int i=1;i<=cnt;i++) count+=1ll*l[i].cnt*(l[i].cnt-1)/2; count*=C[rnt][k]; ans+=((rnt-k)%2?-1:1)*count; } int main() { C[0][0]=1; for (int i=1;i<=6;i++) { C[i][0]=1; for (int j=1;j<=i;j++) C[i][j]=C[i-1][j-1]+C[i-1][j]; } scanf("%d%d",&n,&k); for (int i=1;i<=n;i++) for (int j=0;j<6;j++) scanf("%d",&a[i][j]); for (int i=0;i<(1<<6);i++) Calc(i); printf("%lld",ans); }
在日渐沉没的世界里,我发现了你。