BZOJ 3198 Sdoi2013 spring Hash+容斥原理

来源:互联网 发布:三毛淘宝小号交易平台 编辑:程序博客网 时间:2024/06/07 01:15

题目大意:给定n个元素,每个元素是一个六元组,求有多少对元素满足相同的位置恰好有k个

首先对于恰好有K个这种东西果断考虑容斥原理

我们2^6枚举相同的位置

恰好有k个元素相同的对数=至少有k个位置相同的对数-至少有k+1个位置相同的对数+至少有k+2个位置相同的对数……

但是我们计数时会发现一些问题 比如下面这组样例显然是0:

2 3

1 2 3 4 5 5

1 2 3 4 6 6

但是这一对元素被加了C(4,3)次,只被减掉了C(4,4)次

因此我们将公式改成这样:

恰好有k个元素相同的对数=至少有k个位置相同的对数*C(k,k)-至少有k+1个位置相同的对数*C(k+1,k)+至少有k+2个位置相同的对数*C(k+2,k)……

这样就行了

至于统计同一组位置上有多少对相同的元素,可以利用哈希表

首先将这最多6个数利用RK的思想Hash成一个数,然后插入Hash表即可

时间复杂度O(n*2^6)

如果将哈希表改成排序,时间复杂度O(nlogn*2^6),会TLE

#include <cstdio>#include <cstring>#include <iostream>#include <algorithm>#define M 100100#define BASE 999911657using namespace std;const int C[7][7]={{1,0,0,0,0,0,0},{1,1,0,0,0,0,0},{1,2,1,0,0,0,0},{1,3,3,1,0,0,0},{1,4,6,4,1,0,0},{1,5,10,10,5,1,0},{1,6,15,20,15,6,1},};int n,k;int a[M][6];int digit[64];long long ans;namespace Hash_Set{struct List{List *next;unsigned long long hash;int val;List() {}List(List *_,unsigned long long __):next(_),hash(__),val(0) {}}*head[1001001],mempool[M],*C=mempool;int tim[1001001],T;inline void Initialize(){++T;C=mempool;}int& Hash(unsigned long long hash){int pos=hash%1001001;if(tim[pos]!=T)tim[pos]=T,head[pos]=0x0;for(List *temp=head[pos];temp;temp=temp->next)if(temp->hash==hash)return temp->val;head[pos]=new (C++) List(head[pos],hash);return head[pos]->val;}}long long Calculate(int state){using namespace Hash_Set;int i,j;long long re=0;Initialize();for(i=1;i<=n;i++){unsigned long long hash=0;for(j=1;j<=6;j++)if( state&(1<<j-1) )(hash*=BASE)+=a[i][j];int &val=Hash(hash);re+=(val++);}return re;}int main(){int i,j;cin>>n>>k;for(i=1;i<=n;i++)for(j=1;j<=6;j++)scanf("%d",&a[i][j]);for(i=0;i<64;i++){digit[i]=digit[i>>1]+(i&1);if(digit[i]>=k)ans+=(digit[i]-k&1?-1:1)*Calculate(i)*C[digit[i]][k];}cout<<ans<<endl;return 0;}


1 0
原创粉丝点击