bzoj 3198: [Sdoi2013]spring (hash+容斥原理)

3198: [Sdoi2013]spring

Time Limit: 40 Sec   Memory Limit: 256 MB
Submit: 947   Solved: 296
[ Submit][ Status][ Discuss]

Description

Input

Output

Sample Input

3 3
1 2 3 4 5 6
1 2 3 0 0 0
0 0 0 4 5 6

Sample Output

2

HINT


Dragonite修正数据

Source

[ Submit][ Status][ Discuss]

题解:hash+容斥原理

刚开始hxy手残了,WA了,然后一脸惊恐的对着ATP说我不会被卡hash 了吧。。。。结果发现容斥系数貌似不太对啊,负号莫名多了。。。。。

将每个字符串hash,然后可以把k个不同,变成6-k个相同。就可以枚举哪些位置不同,然后消除掉hash中这些位的影响,计算hash值相同的数的个数。

我们在计算k的时候实际包含了0..k-1个位置不同的答案,所以需要容斥一下。

容斥的系数的绝对值就是组合数,至于正负,必然是一正一负交替排列啦。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#define N 200003
#define p 2000001001
#define ull unsigned long long 
#define LL long long
using namespace std;
int n,m,ch[N][10],len,q[100];
ull mi[N],hp[N],hash1[N];
LL ans,base[10][10];
void build()
{
	base[0][0]=1;
	base[1][0]=-6; base[1][1]=1;
	base[2][0]=15; base[2][1]=-5; base[2][2]=1;
	base[3][0]=-20; base[3][1]=10; base[3][2]=-4; base[3][3]=1;
	base[4][0]=15; base[4][1]=-10; base[4][2]=6; base[4][3]=-3; base[4][4]=1;
	base[5][0]=-6; base[5][1]=5; base[5][2]=-4; base[5][3]=3; base[5][4]=-2; base[5][5]=1;
	base[6][0]=1; base[6][1]=-1; base[6][2]=1; base[6][3]=-1; base[6][4]=1; base[6][5]=-1; base[6][6]=1;
}
void solve()
{
	for (int i=1;i<=n;i++) {
		hash1[i]=hp[i];
		for (int j=1;j<=len;j++) hash1[i]-=(ull)mi[q[j]]*ch[i][q[j]];
	}
	sort(hash1+1,hash1+n+1);
	LL sum=1;
    for (int i=2;i<=n;i++)
     if (hash1[i]==hash1[i-1]) {
	   sum++;
	   if (i==n) ans+=(LL)base[m][len]*sum*(sum-1)/2;
     }
     else {
     	ans+=(LL)base[m][len]*sum*(sum-1)/2;
     	sum=1;
	 }
}
void dfs(int x,int now)
{
	if (x==len+1) {
		//for (int i=1;i<=len;i++) cout<<q[i]<<" ";
		//cout<<endl; 
	//	cout<<ans<<endl;
		solve();
		return;
	}
	for (int i=now;i<=6;i++){
		q[x]=i;
		dfs(x+1,i+1);
	}
}
int main()
{
	freopen("a.in","r",stdin);
	//freopen("my.out","w",stdout);
	scanf("%d%d",&n,&m);
	mi[0]=1;
	for (int i=1;i<=8;i++) mi[i]=mi[i-1]*p;
	for (int i=1;i<=n;i++)
	 for (int j=1;j<=6;j++) scanf("%d",&ch[i][j]),ch[i][j]++;
	for (int i=1;i<=n;i++) 
	 for (int j=1;j<=6;j++) hp[i]+=(ull)mi[j]*(ull)ch[i][j];
	build(); m=6-m;
	for (int i=0;i<=m;i++) {
		len=i;
		dfs(1,1);
	}
	printf("%I64d\n",ans);
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值