洛谷传送门
BZOJ传送门
题目描述
作为光荣的济南泉历史研究小组中的一员,铭铭收集了历史上 x x x个不同年份时不同泉区的水流指数,这个指数是一个小于 2 30 2^{30} 230的非负整数。第 i i i个年份时六个泉区的泉水流量指数分别为 A ( i , 1 ) , A ( i , 2 ) , A ( i , 3 ) , A ( i , 4 ) , A ( i , 5 ) A(i,1),A(i,2),A(i,3),A(i,4), A(i,5) A(i,1),A(i,2),A(i,3),A(i,4),A(i,5)与 A ( i , 6 ) A(i,6) A(i,6)。
现在铭铭希望知道有多少对不同的年份: i i i和 j j j,满足这两年恰好有 K K K个泉区的泉水流 S S S指数对应相同。
输入输出格式
输入格式:
第一行有 2 2 2个整数,分别是 N N N和 K K K
之后 N N N行,每行有 6 6 6个整数。第 i i i行的第 j j j个数字 A ( i , j ) A(i,j) A(i,j)表示第 i i i个年份中第 j j j个泉区的泉水流量指数。
输出格式:
一个整数表示有多少对不同的年份满足恰有 K K K个区的泉水流量指数对应相同。
输入输出样例
输入样例#1:
3 3
1 2 3 4 5 6
1 2 3 0 0 0
0 0 0 4 5 6
输出样例#1:
2
说明
对于 100%的数据, 0 ≤ K ≤ 6 0\le K \le 6 0≤K≤6, 且所有数据中 K K K是等概率出现的, 即对于任意的 0 ≤ x 0\le x 0≤x都有大约 1 / 7 1/7 1/7 的数据中 K = x K=x K=x. N ≤ 100000 N\le 100000 N≤100000
解题分析
很显然的容斥, 我们先可以用哈希算出来至少有 K K K个, K + 1 K+1 K+1… 6 6 6个相同的对数, 设这些值为 f ( K ) , f ( K + 1 ) . . . f ( 6 ) f(K),f(K+1)...f(6) f(K),f(K+1)...f(6)。再设 g ( K ) , g ( K + 1 ) , . . . , g ( 6 ) g(K),g(K+1),...,g(6) g(K),g(K+1),...,g(6)为恰好这么多相同的对数
显然, g ( K + 1 ) g(K+1) g(K+1)对 f ( K ) f(K) f(K)的贡献是 ( K + 1 K ) \binom{K+1}{K} (KK+1)次, 对 g ( K + 2 ) g(K+2) g(K+2)的贡献是 ( K + 2 K ) \binom{K+2}{K} (KK+2)次… ,大概是这样的:
f ( K ) = f(K)= f(K)= | f ( K + 1 ) = f(K+1)= f(K+1)= | f ( K + 2 ) = f(K+2)= f(K+2)= | |
---|---|---|---|
g ( K ) g(K) g(K) | ( K K ) \binom{K}{K} (KK) | ||
g ( K + 1 ) g(K+1) g(K+1) | ( K + 1 K ) \binom{K+1}{K} (KK+1) | ( K + 1 K + 1 ) \binom{K+1}{K+1} (K+1K+1) | |
g ( K + 2 ) g(K+2) g(K+2) | ( K + 2 K ) \binom{K+2}{K} (KK+2) | ( K + 2 K + 1 ) \binom{K+2}{K+1} (K+1K+2) | ( K + 2 K + 2 ) \binom{K+2}{K+2} (K+2K+2) |
这是不能直接容斥的, 但观察可得每一列的下指标一样, 那么其中每一项乘上 ( K + m K ) \binom{K+m}{K} (KK+m)后, 就变成了:
K K K | K + 1 K+1 K+1 | K + 2 K+2 K+2 | |
---|---|---|---|
K K K | ( K K ) ( 0 0 ) \binom{K}{K}\binom{0}{0} (KK)(00) | ||
K + 1 K+1 K+1 | ( K + 1 K ) ( 1 0 ) \binom{K+1}{K}\binom{1}{0} (KK+1)(01) | ( K + 1 K ) ( 1 1 ) \binom{K+1}{K}\binom{1}{1} (KK+1)(11) | |
K + 2 K+2 K+2 | ( K + 2 K ) ( 2 0 ) \binom{K+2}{K}\binom{2}{0} (KK+2)(02) | ( K + 2 K ) ( 2 1 ) \binom{K+2}{K}\binom{2}{1} (KK+2)(12) | ( K + 2 K ) ( 2 2 ) \binom{K+2}{K}\binom{2}{2} (KK+2)(22) |
就可以容斥了…
auto真好用
代码如下:
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <vector>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define BASE 666233ll
#define MOD1 100003ll
#define ll long long
#define MOD2 19260817ll
#define MX 100500
template <class T>
IN void in(T &x)
{
x = 0; R char c = gc;
for (; !isdigit(c); c = gc);
for (; isdigit(c); c = gc)
x = (x << 1) + (x << 3) + c - 48;
}
struct INFO {int key, cnt;};
std::vector <INFO> buc[MOD1];
int n, k;
long long ans, res;
int dat[MX][6], C[7][7], tar[7];
IN void insert(ll key1, ll key2)
{
for (auto &i : buc[key1]) if (i.key == key2) return i.cnt++, void();
buc[key1].push_back({key2, 1});
}
IN void count()
{
for (R int i = 0; i < MOD1; ++i)
{
for (auto j : buc[i]) res += 1ll * j.cnt * (j.cnt - 1) / 2;
std::vector <INFO> ().swap(buc[i]);
}
}
IN void work(R int typ)
{
int tot = 0; ll hs1, hs2;
for (R int i = 0; i < 6; ++i) if (typ & (1 << i)) tar[++tot] = i;
for (R int i = 1; i <= n; ++i)
{
hs1 = hs2 = 0;
for (R int j = 1; j <= tot; ++j)
{
hs1 = (hs1 * BASE % MOD1 + dat[i][tar[j]]) % MOD1;
hs2 = (hs2 * BASE % MOD2 + dat[i][tar[j]]) % MOD2;
}
insert(hs1, hs2);
}
count();
}
int main(void)
{
in(n), in(k);
for (R int i = 1; i <= n; ++i)
for (R int j = 0; j < 6; ++j) in(dat[i][j]);
for (R int i = 0; i <= 6; ++i) C[i][0] = 1;
for (R int i = 1; i <= 6; ++i)
for (R int j = 1; j <= i; ++j)
C[i][j] = C[i - 1][j - 1] + C[i - 1][j];
for (int i = 0; i <= 63; ++i)
{
int cnt = __builtin_popcount(i);
if (cnt < k) continue;
res = 0; work(i);
if ((k - cnt) & 1) ans -= res * C[cnt][k];
else ans += res * C[cnt][k];
}
printf("%lld", ans);
}