卧薪尝胆,厚积薄发。
SDOI2013 泉
Date: Sat Sep 08 16:36:40 CST 2018
In Category:
NoCategory
Description:
有
$n$
组,每组六个数,输出有几对组恰好有
$k$
个值相同。
$1\le n \le 10^5,0\le k\le 6$
Solution:
我一开始的思路是,先
$2^6=64$
枚举所有情况,然后用
$hash$
求出这些位相同的对数,只要把
$hash$
值存到一个
$hash$
表里统计即可,然后利用容斥原理:恰好有
$k$
个值相同的对数
$=$
大于等于
$k$
个值相同的对数
$-$
大于等于
$k+1$
个值相同的对数
$+$
大于等于
$k+2$
个值相同的对数
$\cdots$
,这样直接统计当前枚举的情况中有几个一,就把对应计数器加一然后最后容斥。
然而这题并没有这么简单,这题的容斥系数并不是简单的
$\pm1$
,因为对于这样一组数据(来自popoqqq):
2 3
1 2 3 4 5 5
1 2 3 4 6 6
答案是
$0$
,但是
$1$
和
$2$
这一对被计算了
$C_4^3$
次,被减掉了
$C_4^4$
次,也就是说一个
$k+x$
情况其实可以容斥掉很多
$k$
的情况,具体来说,是
$C_{k+x}^k$
个,于是按这个系数容斥即可。
$hash$
我用的三底数
$+$
自然溢出。
Code:
#include<algorithm>
#include<iostream>
#include<cstdlib>
#include<cstdio>
#include<cmath>
#include<cstring>
using namespace std;
int n,k;
#define MAXN 100001
typedef unsigned long long ll;
ll a[MAXN][7];
ll C[7][7];
ll S[7];
const ll MOD = 19260817ull;
const ll BASE1 = 99997ull;
const ll BASE2 = 1001001ull;
const ll BASE3 = 1000003ull;
int head[MOD],nxt[MAXN];
ll state1[MAXN],state2[MAXN],state3[MAXN],cnt[MAXN];
int num;
inline void add(ll k1,ll k2,ll k3)
{
register int hash = k1 % MOD;
for(register int i = head[hash];i != 0;i = nxt[i])
if(state1[i] == k1 && state2[i] == k2 && state3[i] == k3){++cnt[i];return;}
++num;state1[num] = k1;state2[num] = k2;state3[num] = k3;cnt[num] = 1;nxt[num] = head[hash];head[hash] = num;
return;
}
inline ll query(ll k1,ll k2,ll k3)
{
register int hash = k1 % MOD;
for(register int i = head[hash];i != 0;i = nxt[i])
if(state1[i] == k1 && state2[i] == k2 && state3[i] == k3)return cnt[i];
return 0;
}
inline int bitcnt(int b)
{
register int res = 0;
while(b > 0)
{
if(b & 1)++res;
b = b >> 1;
}
return res;
}
ll hashres[MAXN][4];
int main()
{
scanf("%d%d",&n,&k);
for(int i = 1;i <= n;++i)
for(int j = 1;j <= 6;++j)
cin >> a[i][j];
C[0][0] = 1;
for(register int i = 1;i <= 6;++i)
{
C[i][0] = 1;
for(register int j = 1;j <= 6;++j)
C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
}
register int tot = (1 << 6) - 1;
memset(S,0,sizeof(S));
for(register int b = 0;b <= tot;++b)
{
num = 0;
register int cnt = bitcnt(b);
register ll sum = 0;
for(register int i = 1;i <= n;++i)
{
hashres[i][1] = hashres[i][2] = hashres[i][3] = 0;
for(register int j = 1;j <= 6;++j)
{
if(b & (1 << (j - 1)))
{
hashres[i][1] = hashres[i][1] * BASE1 + a[i][j];
hashres[i][2] = hashres[i][2] * BASE2 + a[i][j];
hashres[i][3] = hashres[i][3] * BASE3 + a[i][j];
}
}
sum += query(hashres[i][1],hashres[i][2],hashres[i][3]);
add(hashres[i][1],hashres[i][2],hashres[i][3]);
}
S[cnt] += sum;
for(register int i = 1;i <= n;++i)head[hashres[i][1] % MOD] = 0;
}
ll ans = 0;
for(register ll i = k,tag = 1;i <= 6;++i,tag = -tag)ans = ans + S[i] * tag * C[i][k];
printf("%lld\n",ans);
return 0;
}
Copyright © 2020
wjh15101051
ღゝ◡╹)ノ♡