Gold Balanced Lineup
Time Limit: 2000MS | Memory Limit: 65536K | |
Total Submissions: 17741 | Accepted: 4973 |
Description
Farmer John's N cows (1 ≤ N ≤ 100,000) share many similarities. In fact, FJ has been able to narrow down the list of features shared by his cows to a list of only K different features (1 ≤ K ≤ 30). For example, cows exhibiting feature #1 might have spots, cows exhibiting feature #2 might prefer C to Pascal, and so on.
FJ has even devised a concise way to describe each cow in terms of its "feature ID", a single K-bit integer whose binary representation tells us the set of features exhibited by the cow. As an example, suppose a cow has feature ID = 13. Since 13 written in binary is 1101, this means our cow exhibits features 1, 3, and 4 (reading right to left), but not feature 2. More generally, we find a 1 in the 2^(i-1) place if a cow exhibits feature i.
Always the sensitive fellow, FJ lined up cows 1..N in a long row and noticed that certain ranges of cows are somewhat "balanced" in terms of the features the exhibit. A contiguous range of cows i..j is balanced if each of the Kpossible features is exhibited by the same number of cows in the range. FJ is curious as to the size of the largest balanced range of cows. See if you can determine it.
Input
Line 1: Two space-separated integers, N and K.
Lines 2..N+1: Line i+1 contains a single K-bit integer specifying the features present in cow i. The least-significant bit of this integer is 1 if the cow exhibits feature #1, and the most-significant bit is 1 if the cow exhibits feature #K.
Output
Line 1: A single integer giving the size of the largest contiguous balanced group of cows.
Sample Input
7 3
7
6
7
2
1
4
2
Sample Output
4
Hint
In the range from cow #3 to cow #6 (of size 4), each feature appears in exactly 2 cows in this range
直接想法:从 i 到 j 范围内的奶牛同一列的特征值相加相等,取 j-i+1 的最大值。
直接模拟这种思想我们需要用到三重for循环,超时是大概率情况。所以这个时候我们应该要想到使用一些算法来减小时间复杂度。这道题中我们需要用到的就是前缀和的思想。
我们令 sumi(a, b, c) 为i与i之前的牛的特征的和,sumj(e, f, g)同理(j>i)。如果 i---j 构成最大平衡区间,那么会有 sumj - sumi = (e-a, f-b, g-c) = (x, x, x)(x为正整数或0),即 sumi(a, b, c) + (x, x, x) = sumj(e, f, g) → (a+x, b+x, c+x) = (e, f, g)。统一减去第一列值后有(0, b-a, c-a) = (0, f-e, g-e)。所以这个时候我们只需要判断两个数组内相同列的值是否相等,就可以找到平衡区间。需要注意的是:当sumi内不同列的值全部相等时,就说明此时的下标 i 同样为一个平衡区间(从0位开始计算的特征值平衡)
所以步骤如下:
一、将题中所给样例数据化为二进制数(特征值从哪个方向存放其实无所谓,我们只要求 i-j 内的特征值相加相等就行)
编号 特征
① 1 1 1
② 1 1 0
③ 1 1 1
④ 0 1 0
⑤ 0 0 1
⑥ 1 0 0
⑦ 0 1 0
二、这时我们让每一行的数字都与前一行的数字相加,即第 i 行 j 列的数字表示前 i 行前 j 列的值的和
编号 特征
① 1 1 1
② 2 2 1
③ 3 3 2
④ 3 4 2
⑤ 3 4 3
⑥ 4 4 3
⑦ 4 5 3
三、判断是否存在sumi(a, b, c) a=b=c 的情况,如果存在,判断与maxlen(最大平衡区间)哪个更大
四、全部减去第一列(注意存在负数情况,所以我们使用哈希时key值需要取绝对值)
编号 特征
① 0 0 0
② 0 0 -1
③ 0 0 -1
④ 0 1 -1
⑤ 0 1 0
⑥ 0 0 -1
⑦ 0 1 -1
五、哈希 key = (sum[][j] + ...)*4%prime (这里我的prime取小于100000的最小素数99991,可以随意取,只要能分散开就行)
六、找到最大平衡区间
1. 看是否考虑到了sumi每列值相等的情况
2. 如果输入的n为1只有一头牛,那么输出不能为零,要为1 (我是没明白为什么还要这种操作,直接为零不行吗?)。如果输入的n>1超过一头牛,那么输出有可能为零(不存在平衡区间)
3. 如果还是WA,多半哈希有问题
别着急,POJ讨论区有位大神给出了部分测试数据,测试下你就知道了。
网址:http://poj.org/showmessage?message_id=346489
以下是我的代码:(用时891MS)
#include
#include
#include
#include
#include
#include
using namespace std;
const int Max =100005;
const int prime = 99991; //一般prime值取小于最大区间k倍的最大素数
int sum[Max][35];
int C[Max][35]; //sum数组中的每一行的每一列都减去第一列的值
vectorHash[Max]; //vector模拟链表
int k;
int maxlen=0; //最大平衡特征值
void Hash_cache(int *cc, int site){ //哈希,cc为C数组中的第i行数组,site参数的值为i
int key = 0;
for( int j=0; jmaxlen )
{
maxlen = site-Hash[key][c]; //因为是前缀和所以不需要+1
}
}
}
Hash[key].push_back(site);
}
}
int main(){
int n,x;
int key;
bool E=true; //判断是否会出现sum各值都相等
scanf("%d %d",&n,&k);
scanf("%d",&x);
if( n==1 ) { printf("1\n"); return 0; } //特殊情况:当只有一头牛时,连续 1 头牛的特征平衡
for( int j=0; j>=1;
}
//第一头牛直接存入sum,从第二头开始特征与前头牛相应特征相加
for( int i=1; i>=1;
}
if( E==true && (i+1)>maxlen ){ //平衡区间存在时
maxlen = i+1;
}
Hash_cache(C[i], i);
}
printf("%d\n",maxlen);
return 0;
}
/*
1. 将特征按照二进制位存入sum[][]数组中
2. 查看是否是平衡(当sum[i]中的各数都相同时,明显此时为平衡区间)
3. sum所有行减去第一列
4. 哈希
5. 查找找到最大差距
*/
参考博客:https://blog.csdn.net/alongela/article/details/8246612