您的位置:首页 > 编程语言 > Java开发

[BZOJ3198][Sdoi2013]spring(hash+容斥原理+组合数学)

2017-03-22 10:57 309 查看

题目描述

传送门

题解

可以通过枚举+hash求出有i位对应相同有多少对

设其为f(i)

那么答案应该为f(k)∗Ckk−f(k+1)∗Ckk+1...f(6)∗Ck6

容斥系数是组合数的原因是即使不考虑有i为对应相同的和有i+1位对应相同的有交集,还是会选出很多重复的情况,所以应该同时将其去重

刚开始hash挂了一个map,T成狗…

实际上排个序就能快很多

代码

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<map>
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 <UL,LL> mp;

int cmp(data a,data b)
{
return a.cnt<b.cnt||(a.cnt==b.cnt&&a.val<b.val);
}
int 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);
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: