传送门
可以通过枚举+hash求出有i位对应相同有多少对
设其为f(i)
那么答案应该为 f(k)∗Ckk−f(k+1)∗Ckk+1...f(6)∗Ck6
容斥系数是组合数的原因是即使不考虑有i为对应相同的和有i+1位对应相同的有交集,还是会选出很多重复的情况,所以应该同时将其去重
刚开始hash挂了一个map,T成狗…
实际上排个序就能快很多
#include
#include
#include
#include
#include
#include
using namespace std;
#define LL long long
#define UL unsigned long long
const UL S=200001001LL;
int n,k;
int a[100005][10],cnt[100],l[10],r[10];
LL mul[10],now,sum,ans;UL mi[10],hash[100005];
struct data{int cnt,val;}sta[100];
map
mp;
int cmp(data a,data b)
{
return a.cntint main()
{
scanf("%d%d",&n,&k);
mi[0]=1;for (int i=1;i<=6;++i) mi[i]=mi[i-1]*S;
mul[0]=1;for (int i=1;i<=6;++i) mul[i]=mul[i-1]*(LL)i;
for (int i=1;i<=n;++i)
for (int j=5;j>=0;--j)
scanf("%d",&a[i][j]);
for (int i=1;i<1<<6;++i)
{
sta[i].val=i;
for (int j=0;j<6;++j)
if ((i>>j)&1) ++sta[i].cnt;
}
sort(sta+1,sta+(1<<6),cmp);
for (int i=1;i<1<<6;++i)
{
if (sta[i].cnt!=sta[i-1].cnt) l[sta[i].cnt]=i;
if (sta[i].cnt!=sta[i+1].cnt) r[sta[i].cnt]=i;
}
for (int i=k,f=1;i<=6;++i,f=-f)
{
sum=0;
if (!i)
{
ans+=(LL)n*(n-1)/2*f;
continue;
}
for (int p=l[i];p<=r[i];++p)
{
int val=sta[p].val;
for (int j=1;j<=n;++j)
{
hash[j]=0;
for (int q=0;q<6;++q)
if ((val>>q)&1) hash[j]+=(UL)a[j][q]*mi[q];
}
now=0;
sort(hash+1,hash+n+1);
for (int j=1;j<=n;++j)
if (hash[j]==hash[j-1]) ++now;
else sum+=now*(now-1)/2,now=1;
sum+=now*(now-1)/2;
}
ans+=sum*mul[i]/mul[i-k]/mul[k]*f;
}
printf("%lld\n",ans);
}