题目描述
给出个维坐标,求有多少对点对满足恰好个位置相等
坐标数值在以内
题目分析
这道题一看就是hash容斥原理,用个位置对应相等个位置对应相等个位置对应相等的…
但是不能简简单单直接,根据广义容斥,还要乘上容斥系数
双,过程中遇到相同但不同的就往后平移,用数组存一下为时的值与值
注意此处数要大于
考试时没用双Hash,想到了做法,奈何代码太丑,这题爆0了…
AC code
#include <bits/stdc++.h>
using namespace std;
#define LL long long
const int MAXN = 100005;
const int P1 = 137, Mod1 = 9999997;
const int P2 = 167, Mod2 = 7394895;
int num[MAXN][6], c[7][7], kase, n, m;
struct MyHash
{
LL y; int flag, cnt; //y存的是Hash1为当前下标i时的Hash2值
//flag是用int打标记,就不用每次清零了
bool Exist() { return flag == kase; }
}h[Mod1];
LL Ans;
void init()
{
for(int i = 0; i < 7; ++i)
{
c[i][0] = c[i][i] = 1;
for(int j = 1; j < i; ++j)
c[i][j] = c[i-1][j-1] + c[i-1][j];
}
}
inline void MyUnique(LL &x, LL o)
{
while(h[x].Exist() && h[x].y != o) (++x) %= Mod1;
}
bool used[7];
void dfs(int pos, int tot)//枚举当前是求哪几个位置
{
if(pos == 6)
{
if(tot < m) return; //小于m的不用处理
LL sum = 0; ++kase;
for(int i = 1; i <= n; ++i)
{
LL hsh1 = 0, hsh2 = 0;
for(int j = 0; j < 6; ++j) if(used[j])
hsh1 = (hsh1 * P1 % Mod1 + num[i][j]) % Mod1,
hsh2 = (hsh2 * P2 % Mod2 + num[i][j]) % Mod2;
MyUnique(hsh1, hsh2);
if(h[hsh1].flag < kase)
h[hsh1].cnt = 0, h[hsh1].flag = kase;
h[hsh1].y = hsh2, sum += (h[hsh1].cnt++);
}
Ans += sum * (((tot-m)&1) ? -1 : 1) * c[tot][m]; //容斥
return;
}
used[pos] = 1;
dfs(pos+1, tot+1);
used[pos] = 0;
dfs(pos+1, tot);
}
int main ()
{
scanf("%d%d", &n, &m); init();
for(int i = 1; i <= n; ++i)
for(int j = 0; j < 6; ++j)
scanf("%d", &num[i][j]);
dfs(0, 0);
printf("%lld
", Ans);
}