题意

\(n\)个年份,每个年份有\(6\)个水流指数\(A(i,1),A(i,2)\)\(A(i,6)\)
问有多少对年份满足恰好有\(k\)个水流指数相同。

思路

容斥+二项式反演
转为钦定\(i\)个相同,其余随便放(也就至少的意思)
\(2^6\)枚举相同的集合,我本来是把对应位取出来排序的,但太慢了。
哈希挂链法是个好东西,跑得又快,接近\(O(1)\),而且没有冲突。

code

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=2e5+5,bs=233,mod=1e7+33;
const int M=mod+5;
typedef long long ll;
int n,k,a[N][7],b[N][7],ecnt,head[M],to[N],nxt[N],cnt[N];

ll C[7][7];

bool check(int s,int x,int y) {	//位数s下x和y是否相同 
	for(int i=0;i<6;i++) {
		if(s&(1<<i)) {
			if(a[x][i]!=a[y][i])return 0;
		}
	}
	return 1;
}
int st[N],tp;
void solve() {
	ll ans=0;
	for(int s=0,up=1<<6;s<up;s++) {
		int ppc=0;
		for(int i=0;i<6;i++) {if((1<<i)&s) ppc++;}
		if(ppc<k) continue;
		ll res=0;
		for(int i=1;i<=n;i++) {
			ll x=0;
			for(int j=0;j<6;j++) {if((1<<j)&s){x=(x*bs+a[i][j])%mod;}}
			int j=head[x];
			for(;j;j=nxt[j]) {
				if(check(s,to[j],i)) {res+=cnt[j]++;break;}
			}
			if(!j){nxt[++ecnt]=head[x];to[ecnt]=i;cnt[ecnt]=1;head[x]=ecnt;st[++tp]=x;}
		}
		res*=C[ppc][k];
		ans+=(ppc-k)&1?-res:res;
		
		ecnt=0;for(int i=1;i<=tp;i++)head[st[i]]=0;tp=0;
	}
	printf("%lld",ans);
}

int main() {
	scanf("%d%d",&n,&k);
	for(int i=1;i<=n;i++)for(int j=0;j<6;j++)scanf("%d",&a[i][j]);
	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];
	}
	solve();
	return 0;
}