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

bzoj3198 [sdoi2013] spring 哈希挂表+容斥

2018-01-28 21:47 375 查看
6这个数据非常小,而且hash只能用来匹配,并不能检验完全不匹配,对于处于对立面的小数据就需要使用大型暴力容斥

但这个题超级卡hash,不知道是数据的锅还是题目本身的性质,直接上双hash都过不了

首先hash是被hash的数规模越小越不容易错,所以对于枚举每个数容斥不如先容斥再枚举每个数,这样容斥的位数确定就可以单独使用hash,规模会小很多,所以就是用了hash挂表。先正常用long long自然溢出,然后再用一个模数来挂

码:

#include<iostream>
#include<cstdio>
using namespace std;
#define jz 1000003
#define P 2150527
int lin,n,k,er[9],xia[P+10],hou[100005];
long long a[100005][9],sum[P],c[9][9],daan,v[100005];
int vis[P];
long long work(int o)
{
int i,j,ans=0,k,tot=0;
for(i=1;i<=n;i++)
{
long long tmp=0;
for(j=0;j<6;j++)
if(er[j]&o)tmp=tmp*jz+a[i][j+1];
j=tmp%P;if(j<0)j+=P;else j++;
if(vis[j]!=o)vis[j]=o,xia[j]=0;

for(k=xia[j];k;k=hou[k]){
if(v[k]==tmp){
ans+=sum[k];sum[k]++;
break;
}
}
if(!k){
v[++tot]=tmp;
sum[tot]=1;hou[tot]=xia[j];xia[j]=tot;
}

}
return ans;
}

int main()
{
int i,j;
scanf("%d%d",&n,&k);
c[0][0]=1;for(i=1;i<=6;i++){c[i][0]=1;for(j=1;j<=i;j++)c[i][j]=c[i-1][j-1]+c[i-1][j];}
er[0]=1;
for(i=1;i<=7;i++)er[i]=er[i-1]*2;
for(i=1;i<=n;i++)for(j=1;j<=6;j++)scanf("%lld",&a[i][j]);
for(i=0;i<er[6];i++)
{
int lin=0;
for(j=0;j<6;j++)if(i&er[j])++lin;
if(lin<k)continue;
long long flg=1;
if((lin&1)!=(k&1))flg=-1;
daan+=work(i)*c[lin][k]*flg;
}
printf("%lld",daan);

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: