Description
有n条河流,每条河流有6个特征。对于给定的k,求多少对河流有恰好k个特征相等
n
≤
1
0
5
n\le10^5
n≤105
Solution
知道了套路就驾轻就熟了。。
我们只需要求出至少k个特征的答案,那么26枚举这些特征然后用hash判一下,最后套一个容斥就可以了
嗯,似乎非常简单,至少看起来是这样的
但是这里的hash似乎需要一些高超技巧,我们简单地当成6位BASE进制膜一个大质数是行不通的。。。
本着发扬OI不是口胡竞赛的愿景,我对着一个标膜了又膜终于只拿到了92分。一波换质数+换底数都没有成功A掉。。直接上map又会T掉,想了想还是不管了。。
综上,这是一份不能AC的92分代码╮(╯▽╰)╭
Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define rep(i,st,ed) for (register int i=st;i<=ed;++i)
#define fill(x,t) memset(x,t,sizeof(x))
typedef long long LL;
const int MOD=1234567;
const int N=500100;
LL a[N][10],n;
LL c[10][10];
struct Hash {
int tot,h[MOD+10],v[MOD+10];
LL rec[MOD+10];
void clear() {
rep(i,1,tot) rec[v[i]]=h[v[i]]=0;
tot=0;
}
LL calc() {
LL res=0;
rep(i,1,tot) {
if (rec[v[i]]&1) {
res+=(rec[v[i]]-1)/2*rec[v[i]];
} else res+=rec[v[i]]/2*(rec[v[i]]-1);
}
return res;
}
bool equal(int x,int y,int S) {
bool flag=true;
rep(i,0,5) if ((S>>i)&1) flag&=(a[x][i+1]==a[y][i+1]);
return flag;
}
void insert(int tmp,int pos,int S) { tmp%=MOD;
while (h[tmp]&&!equal(h[tmp],pos,S)) tmp=(tmp+1)%MOD;
if (!h[tmp]) v[++tot]=tmp,h[tmp]=pos;
rec[tmp]++;
}
} Hash;
int read() {
int x=0,v=1; char ch=getchar();
for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar());
for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar());
return x*v;
}
LL calc(int S) {
Hash.clear();
rep(i,1,n) {
LL tmp=0;
rep(j,1,6) {
tmp=tmp*233%MOD;
if ((S>>(j-1))&1) tmp=(tmp+a[i][j]+1)%MOD;
}
Hash.insert(tmp,i,S);
}
return Hash.calc();
}
int main(void) {
freopen("data.in","r",stdin);
n=read(); int k=read();
c[1][0]=c[1][1]=1;
rep(i,2,7) {
c[i][0]=1;
rep(j,1,i) c[i][j]=c[i-1][j]+c[i-1][j-1];
}
rep(i,1,n) rep(j,1,6) a[i][j]=read();
LL ans=0;
for (int S=0;S<64;++S) {
int cnt=__builtin_popcount(S);
if (cnt<k) continue;
LL xs=((cnt-k)&1)?-1:1;
ans+=xs*calc(S)*c[cnt][k];
}
printf("%lld\n", ans);
return 0;
}