洛谷P3298 泉

时空限制 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个区的泉水流量指数对应相同。

输入输出样例

输入样例#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, 且所有数据中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\n", fin);
115     return 0;
116 }
AC代码

 

 

 

posted @ 2019-05-06 20:40  huyufeifei  阅读(137)  评论(0编辑  收藏  举报
试着放一个广告栏(虽然没有一分钱广告费)

『Flyable Heart 応援中!』 HHG 高苗京铃 闪十PSS 双六 電動伝奇堂 章鱼罐头制作组 はきか 祝姬 星降夜