时空限制 1000ms / 128MB
题目描述
作为光荣的济南泉历史研究小组中的一员,铭铭收集了历史上x个不同年份时不同泉区的水流指数,这个指数是一个小于. 2^30的非负整数。第i个年份时六个泉区的泉水流量指数分别为 A(i,l),A(i,2),A(i,3),A(i,4), A(i,5)与 A(i,6)。
现在铭铭希望知道有多少对不同的年份:i和j,满足这两年恰好有K个泉区的泉水流S指数对应相同。
输入输出格式
输入格式:第一行有2个整数,分别是N和K
之后N行,每行有6个整数。第i行的第j个数字A(i,j)表示第i个年份中第j个泉区的泉水流量指数。
输出格式:一个整数表示有多少对不同的年份满足恰有K个区的泉水流量指数对应相同。
输入输出样例
说明
对于 100%的数据, 0<=K <=6, 且所有数据中K是等概率出现的, 即对于任意的 0<=x都有大约 1/7 的数据中 K=x. N<=100000
解:稍加思索,发现我们可以枚举是哪k个相等,但是这样会算重,所以容斥一下。发现26 = 64,有搞头。
这样问题转化成了给定一个6元组组成的序列,判断其中有多少个相等的。显然只要hash就行了。那么如何对一个6元组hash呢?red sun一语惊醒我:字符串hash啊。
注意这题容斥的时候要乘组合数,可能只有我没乘组合数还一直以为是hash的锅......
1 #include <bits/stdc++.h> 2 3 typedef unsigned long long uLL; 4 typedef long long LL; 5 const int N = 100010; 6 const uLL B = 131, MO = 998244353; 7 8 uLL pwB[50], h[N][6], pw2[50], h2[N][6]; 9 int a[N][6], n, k, cnt[70], pw[N]; 10 LL C[10][10]; 11 12 inline uLL getHash(int x) { 13 uLL ans = 0; 14 for(int i = 0; i < 10; i++) { 15 ans = ans * B + (x % 10) + '0'; 16 x /= 10; 17 } 18 return ans; 19 } 20 inline uLL getHash2(int x) { 21 uLL ans = 0; 22 for(int i = 0; i < 30; i++) { 23 ans = (ans * B % MO + (x & 1) + '0') % MO; 24 x >>= 1; 25 } 26 return ans; 27 } 28 29 namespace Hash { 30 struct Node { 31 int cnt, nex; 32 uLL val, val2; 33 }node[N]; int tp; 34 const int mod = 999983; 35 int e[mod]; 36 inline int insert(uLL v, uLL v2) { 37 int x = v % mod; 38 for(int i = e[x]; i; i = node[i].nex) { 39 if(node[i].val == v && node[i].val2 == v2) { 40 return node[i].cnt++; 41 } 42 } 43 node[++tp].val = v; 44 node[tp].val2 = v2; 45 node[tp].cnt = 1; 46 node[tp].nex = e[x]; 47 e[x] = tp; 48 return 0; 49 } 50 inline void clear() { 51 memset(e, 0, sizeof(e)); 52 tp = 0; 53 return; 54 } 55 } 56 57 int main() { 58 for(int i = 0; i <= 6; i++) { 59 C[i][0] = C[i][i] = 1; 60 for(int j = 1; j < i; j++) { 61 C[i][j] = C[i - 1][j] + C[i - 1][j - 1]; 62 } 63 } 64 scanf("%d%d", &n, &k); 65 for(int i = 1; i <= n; i++) { 66 for(int j = 0; j < 6; j++) { 67 scanf("%d", &a[i][j]); 68 h[i][j] = getHash(a[i][j]); 69 h2[i][j] = getHash2(a[i][j]); 70 } 71 } 72 73 int lm = (1 << 6); 74 for(int s = 1; s < lm; s++) { 75 cnt[s] = 1 + cnt[s - (s & (-s))]; 76 } 77 pw2[0] = pwB[0] = 1; 78 for(int i = 0; i < 6; i++) { 79 pw[1 << i] = i; 80 } 81 for(int i = 0; i < 30; i++) { 82 pwB[i + 1] = pwB[i] * B; 83 pw2[i + 1] = pw2[i] * B % MO; 84 } 85 LL fin = 0; 86 for(int s = 0; s < lm; s++) { 87 if(cnt[s] < k) { 88 continue; 89 } 90 LL ans = 0; 91 Hash::clear(); 92 for(int i = 1; i <= n; i++) { 93 uLL temp = 0, t2 = 0; 94 int ss = s; 95 while(ss) { 96 97 int t = pw[ss & (-ss)]; 98 temp = temp * pwB[6] + h[i][t]; 99 t2 = (t2 * pw2[30] % MO + h2[i][t]) % MO; 100 101 ss ^= (1 << t); 102 } 103 ans += Hash::insert(temp, t2); 104 } 105 ans = ans * C[cnt[s]][k]; 106 if((cnt[s] - k) & 1) { 107 fin -= ans; 108 } 109 else { 110 fin += ans; 111 } 112 } 113 114 printf("%lld ", fin); 115 return 0; 116 }