题目大意
懒惰的人不想复制题面了~
给出n(n<10 0000)个六元组,再给出一个k
求有多少对六元组中有恰好k个相同(对应的位置相同)
Sample Input
5 8 2
1 2 5 8
2 5 9 9
5 1 6 2
5 1 1 8
1 2 8 7
2 5 4 9
1 2 1 1
1 4 2 1
Sample Output
13 19
Solution
显然,我们可以枚举哪几位相同,然后使用hash判断相同的个数。
同时,因为要求的是恰好k个相同,所以要减去k+1个相同,加上k+2个相同……
而且,因为一对有n个相同的六元组,对答案贡献会是
Ckn
C
n
k
倍的,所以要乘上去。
我就是因为c[0][0]没有赋初值,调了超级久,然后被大佬一眼看出(%ymw),惨兮兮(╥╯^╰╥)
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<bitset>
using namespace std;
#define N 150010
#define P1 1000007
#define P2 998244353
#define LL long long
bitset<6> b;
int hash[N][3],last[P1],next[N],t[N],a[N][6];
LL ans[7],c[10][10];
int n,m,tot,cnt;
int find(int num)
{
int x=0;
for (int i=0;i<=5;i++)
if (b[i]==1) x=((LL)x*233+(LL)a[num][i])%P1;
int y=0;
for (int i=0;i<=5;i++)
if (b[i]==1) y=((LL)y*1221+(LL)a[num][i])%P2;
for (int i=last[x];i!=0;i=next[i])
if (hash[i][1]==y) {hash[i][2]++; return i;}
if (last[x]==0) t[++tot]=x;
next[++cnt]=last[x];
last[x]=cnt;
hash[cnt][2]=1;
hash[cnt][0]=x; hash[cnt][1]=y;
return cnt;
}
int main()
{
memset(hash,0,sizeof(hash));
memset(last,0,sizeof(last));
scanf("%d%d",&n,&m);
for (int i=1;i<=n;i++)
for (int j=0;j<=5;j++)
scanf("%d",&a[i][j]);
c[1][1]=1; c[1][0]=c[0][0]=1;
for (int i=2;i<=6;i++)
{
c[i][0]=1;
for (int j=1;j<=i;j++)
c[i][j]=c[i-1][j]+c[i-1][j-1];
}
for (int ii=0;ii<=(1<<6)-1;ii++)
{
b=ii;
int s=b.count();
if (s<m) continue;
for (int l=1;l<=n;l++)
{
int pos=find(l);
int t=hash[pos][2];
ans[s]+=t-1;
}
for (int l=1;l<=tot;l++)
last[t[l]]=0;
tot=0; cnt=0;
}
LL ss=0;
for (int i=m;i<=6;i++)
if ((i-m)%2==0) ss+=ans[i]*c[i][m];
else ss-=ans[i]*c[i][m];
printf("%lld\n",ss);
return 0;
}