bzoj 3198 spring

hash求出每一个子集相等的方案数,按照个数分类,用组合数减去。
这道题的hash要管冲突,hzwer说过,hash冲突的概率是sqrt(md)的。
wa了好久的原因是没有计算ans=0的情况。
有没有大神告诉我为什么要用组合数,不能直接+1-1的加减

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<cmath>

#define md 1234567
#define ll long long
#define inf (int) 1e9
#define eps 1e-8
#define N 1234590
#define cg 23333LL
#define M 500010
using namespace std;
int n;
int a[N][6],c[10][10];
ll ans[7];
bool same(int x,int y,int opt)
{
for (int i=0;i<=5;i++) if ((opt&(1<<i))&&a[x][i]!=a[y][i]) return 0;
return 1;
}

struct ha
{
ll a[N];
int q[N],is[N];
int sz;
ll clear()
{
ll ans=0;
for (int i=1;i<=sz;i++)
{
int x=q[i];
ans+=a[x]*(a[x]-1)/2;
a[x]=is[x]=0;
}
sz=0;
return ans;
}
void insert(int k,int x,int opt)
{
int pos=k;
while (a[pos]&&(!same(x,is[pos],opt))) pos=(pos+1)%md;
if (!a[pos]) q[++sz]=pos,is[pos]=x;
a[pos]++;
}
} hash;

ll solve(int opt)
{
for (int i=1;i<=n;i++)
{
ll ha=0;
for (int j=0;j<=5;j++)
{
ha=ha*cg%md;
if (opt&(1<<j)) { ha=(ha+a[i][j]+1)%md;}
}
hash.insert(ha,i,opt);
}
return hash.clear();
}
int cal(int i)
{
int sum=0;
for (int j=0;j<=5;j++) sum+=(i>>j)&1;
return sum;
}
int main()
{
int k;
scanf("%d%d",&n,&k);
for (int i=1;i<=n;i++)
for(int j=0;j<=5;j++)
scanf("%d",&a[i][j]);
for (int i=0;i<=63;i++) ans[cal(i)]+=solve(i);
c[0][0]=1;
for (int i=1;i<=6;i++)
for (int j=0;j<=i;j++)
c[i][j]=c[i-1][j-1]+c[i-1][j];
for (int i=6;i>=k;i--)
for (int j=0;j<i;j++)
ans[j]-=ans[i]*c[i][j];
printf("%lld\n",ans[k]);
return 0;
}

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值