POJ3274 hash

POJ3274

问题重述:

已知有n头牛,用一个K位二进制数Ak,Ak-1,...,A1表示一头牛具有的特征,Ai=1表示具有特征i。现给定按顺序排列的N头牛的k位特征值,称某个连续范围内“特征平衡”,假如在这个范围内,拥有各个特征的牛的数量都相等。求最大“特征平衡”连续范围。

分析:

用sum[i][j]( 1<=i<=n, 1<=k<=j)表示1到第i头牛中具有特征j的牛的数量。问题转化为求解满足sum[i][l] - sum[j][l] = sum[i][1] - sum[j][1](l = 1,2,..,k)的最大i - j的值。很容易想到最简单的方法,通过令d = n to 1,判断是否存在i,使得sum[i + d][j] - sum[i][j] = sum[i + d][1] - sum[i][j],时间复杂度为O(n*n*k)。由于n的最大值能达到100000,必须选择一个更加优化的方法。

1)容易验证,sum[i][l] - sum[j][l] = sum[i][1] - sum[j][1] ( l = 1,2,..,k ) 等价于sum[i][l] - sum[i][1] = sum[j][l] - sum[j][1] ( l = 1,2,...k )。因此令d[i][j] =  sum[i][j] - sum[i][1] ,问题就转化为求解使得d[i][j] = d[i + size][j]的最大size。

2)为进一步简化算法,对于任意 1<= i <=n, 令sig[i] = (d[i][1] + d[i][2] + ... +d[i][k] ) % m (m为一个较大的质数)。这样,若对于i和j, sig[i] != sig[j],那么必定不会满足d[i][] = d[j][],就无需再对它进行验证;若满足sig[i] = sig[j],才需要进一步确定是否有d[i][] = d[j][]。

3)用h[k] (1 <= k <= m,m为以上取模运算的素数)记录满足sig[i] = k的i值。通过令 i = 1 to n,以此更新h[sig[i]]和largest,即可得到结果。

AC代码

 1 //Memory: 28828K        Time: 469MS
 2 #include <iostream>
 3 #include <cstring>
 4 #include <cstdio>
 5 #include <vector>
 6 #include <cmath>
 7
 8 using namespace std;
 9
10 const int maxn = 100010;
11 const int maxk = 31;
12 int n, k, tmp;
13 bool cow[maxn][maxk];
14 int sum[maxn][maxk];
15 int d[maxn][maxk];
16 int s, size;
17 const int prime = 49117;
18 int sig[maxn];
19 int largest;
20
21 vector <int> h[prime];
22
23 void search(int i, int t)
24 {
25     int size = h[i].size();
26     for (int j = 0; j < size; j++) {
27         bool flag = 1;
28         for (int l = 0; l < k; l++) {
29             if ( d[ h[i][j] ][l] != d[t][l] ) {
30                 flag = 0;
31                 break;
32             }
33         }
34         if (flag) {
35             if (t - h[i][j] > largest)
36                 largest = t - h[i][j];
37             return;
38         }
39     }
40     h[i].push_back(t);
41 }
42
43
44 int findLargest()
45 {
46     largest = 0;
47     for (int i = 1; i <= n; i++) {
48         search(sig[i], i);
49     }
50     return largest;
51 }
52
53 void init()
54 {
55     memset(sum, 0, sizeof(sum));
56     memset(sig, 0, sizeof(sig));
57     for (int i = 0; i < prime; i++) h[i].clear();
58     h[0].push_back(0);
59     for (int i = 1; i <= n; i++) {
60         for (int j = 0; j < k; j++) {
61             sum[i][j] = sum[i - 1][j] + cow[i][j];
62             d[i][j] = sum[i][j] - sum[i][0];
63         }
64         for (int j = 0; j < k; j++) {
65             sig[i] += d[i][j];
66         }
67         sig[i] = abs(sig[i]) % prime;
68     }
69 }
70
71 int main()
72 {
73     //while (1) {
74     scanf("%d%d", &n, &k);
75     for (int i = 1; i <= n; i++ ) {
76         scanf("%d", &tmp);
77         for (int j = 0; j < k; j++) {
78             cow[i][j] = tmp % 2;
79             tmp /= 2;
80         }
81     }
82     init();
83     findLargest();
84     printf("%d\n", largest);
85     //}
86     return 0;
87 }

POJ3274 hash,布布扣,bubuko.com

时间: 2024-10-24 16:16:16

POJ3274 hash的相关文章

Hash小结

Poj1480Eqs a1x13+ a2x23+ a3x33+ a4x43+ a5x53=0 ->a1x13+ a2x23+ a3x3=-(a4x43+ a5x53   问有多少个满足等式的非零x1,x2,x3,x4,x5组.) 中途相遇法,枚举x1,x2,x3得到左边式子的值插入hash表,然后枚举x4,x5找到对应的值就行了. #include <cstdio> #include <cstring> #include <algorithm> #include

poj3274(Gold Balanced Lineup)

题目地址:Gold Balanced Lineup 题目大意: 一个农场有N个奶牛,每个奶牛都有不同的特征,聪明的农夫给奶牛 feature ID.代表奶牛所具有的特征.将feature ID 写成为K位的二进制的数,其中有1的位置代表奶牛具有此特征,0代表没有此特征.从i->j 使这个区间的奶牛所有特征的个数是相等的.其中最大的区间差就是题图所求的. 解题思路: 解题思路: 经典题,不转化问题很难做,先根据官方的方法转化问题,把“求最远的两行间各个特征出现次数相等”转化为“求最远的相同两行”,

一致性hash算法 - consistent hashing

1.背景 我们都知道memcached服务器是不提供分布式功能的,memcached的分布式完全是由客户端来实现的.在部署memcached服务器集群时,我们需要把缓存请求尽可能分散到不同的缓存服务器中,这样可以使得所有的缓存空间都得到利用,而且可以降低单独一台缓存服务器的压力.     最简单的一种实现是,缓存请求时通过计算key的哈希值,取模后映射到不同的memcahed服务器.这种简单的实现在不考虑集群机器动态变化的情况下也是比较有效的一种方案,但是,在分布式集群系统中,简单取模的哈希算法

BZOJ3198 SDOI2013 spring HASH+容斥原理

题意:给定6个长度为n的数列,求有多少个数对(i,j)((i,j)≡(j,i))使得i和j位置恰好有K个数相同,其中0≤K≤6 题解: 设fi=至少有K个数相同的位置对的数量,用2^6枚举每一种可能,根据容斥原理,答案就是\[\sum\limits_{i = K}^N {{f_i}C_i^K{{\left( { - 1} \right)}^{i - K}}} \] 至于多乘一个组合数,是因为当前枚举到有x个数相同,一个位置对有i个相同的数,那么累计的时候就会算成$C_x^i$,因此实际上这个位置

hash算法搜索获得api函数地址的实现

我们一般要获得一个函数的地址,通常采用的是明文,例如定义一个api函数字符串"MessageBoxA",然后在GetProcAddress函数中一个字节一个字节进行比较.这样弊端很多,例如如果我们定义一个杀毒软件比较敏感的api函数字符串,那么可能就会增加杀毒软件对我们的程序的判定值,而且定义这些字符串还有一个弊端是占用的字节数较大.我们想想如何我们的api函数字符串通过算法将它定义成一个4字节的值,然后在GetProcAddress中把AddressOfNames表中的每个地址指向的

BZOJ_3207_花神的嘲讽计划1_(Hash+主席树)

描述 http://www.lydsy.com/JudgeOnline/problem.php?id=3207 给出一个长度为\(n\)的串,以及\(m\)个长度为\(k\)的串,求每个长度为\(k\)的串在原串\([x,y]\)区间是否出现过. 分析 这道题要求对比长度为\(k\)的串,于是我们把这些串的Hash值都算出来,问题就转化成了求\([x,y]\)的区间中是否出现过某Hash值. 求区间中某一个值出现了多少次,可以用主席树. p.s. 1.学习了主席树指针的写法,比数组慢好多啊...

Hash算法专题

1.[HDU 3068]最长回文 题意:求一个字符串(len<=110000)的最长回文串 解题思路:一般解法是manacher,但是这一题用hash也是可以ac的 假设当前判断的是以i为中心偶数最长回文串,那么s[2*i+1-k……i]与s[i+1……k]的哈希值必定相同 假设当前判断的是以i为中心奇数最长回文串,那么s[2*i-k……i-1]与s[i+1……k]的哈希值必定相同 用二分求出相应的k 1 #include <iostream> 2 #include <algori

Salted hash password

参考文档 http://www.cnblogs.com/richardlee/articles/2511321.html https://en.wikipedia.org/wiki/Salt_%28cryptography%29 https://www.91ri.org/7593.html 密码存储为什么不能是明文? 当账户密码是明文存储的话, 万一本网站给黑客攻破获取了数据, 则用户的账户被泄露.(术语叫 拖库) 当黑客知道了你的账户后, 其可以使用此账户,到其他网站尝试访问, 例如有厉害关系

Golang Hash MD4

//Go标准包中只有MD5的实现 //还好,github上有MD4实现. package main import (     "golang.org/x/crypto/md4"     "encoding/hex"     "fmt" ) func get_md4(buf []byte) ([] byte) { ctx := md4.New() ctx.Write(buf) return ctx.Sum(nil) } func main() {