原题链接https://www.luogu.org/problem/P2843
题目描述
敌方的高级将领都是有很多相同之处的。为了方便找到每名敌将的弱点,我军情报部已经找到了他们的不同点,并将其归纳为K种特性。比如1号特性就代表一个敌将喜欢打人,2号特性就代表一个敌将喜欢吃饭,等等。
为了方便存储,我军使用特性值来描述一个敌将的特点。特性值是一个位数为K的二进制整数,每一位都可以表示一名敌将的一个特性。1代表具有此特性,0代表没有。
我军间谍打听到,不久有N个敌方将领会举行一场宴会,而且入场时他们会排成一路纵队入场。如果有连续的M个人的每种特性出现的次数之和是一样的,那么我军间谍就很容易暗杀这M个人。你需要帮助我军算出,间谍最多可以暗杀多少人?
因为间谍开始攻击后就可能被敌人击毙,所以间谍只能进行一次攻击。
样例说明:
ai 属性 敌将
7 1 1 1 1
6 0 1 1 2
7 1 1 1 3
2 0 1 0 4
1 1 0 0 5
4 0 0 1 6
2 0 1 0 7
可以击杀第3人到第6人,共6-3+1=4人
由题意可知我们要找到一段区间其中各个特征和相等,用一个sum数组记录各个特征的前缀和,我们可以得出如果区间[l, r]中各个特征和相等, 那么
\[sum[l][2] - sum[l][1] = sum[r][2] - sum[r][1]\]
\[sum[l][3] - sum[l][1] = sum[r][3] - sum[r][1]\]
....
证明:
当区间[l, r]中各个特征和相等, 设和的值为x
\[sum[r][1] = sum[l][1] + x\]
\[sum[r][2] = sum[l][2] + x\]
...
所以前缀和的相对差值不变。
将前缀和相对差值进行hash,映射到数组中然后用hash值作为key进行匹配,最后进行差值比较确认是否符合。
#include<iostream>
#include<cstdio>
#include<vector>
#define ll long long
using namespace std;
const int N = 1e5 + 10, M = 40, MAX = 1e6 + 10;
int n, k, ans, num;
int lg[M];
int a[N][M], sum[N][M];
vector<int> hash[MAX];
template <typename T>
inline void read(T &x){
x = 0;
char c = getchar();
T op = 1;
for(; c < '0' || c > '9'; c = getchar())
if(c == '-') op = -1;
for(; c <= '9' && c >= '0'; c = getchar())
x = (x << 3) + (x << 1) + c - '0';
x *= op;
}
inline bool check(int x, int y){
for(int i = 1; i <= k; ++i)
if(a[x][i] != a[y][i]) return 0;
return 1;
}//进行精准检验
inline void HASH(int x){
int p = 0;
for(int i = 1; i <= k; ++i)
p += a[x][i] * lg[i], p %= MAX;
p = (p + MAX) % MAX;
int s = hash[p].size();
for(int i = 0; i < s; ++i) //在这人之前是否可以找到一个人进行匹配
if(ans < (x - hash[p][i]))
if(check(x, hash[p][i]))
ans = x - hash[p][i];
hash[p].push_back(x);
return;
}//加入到key为p的hash数组中
inline void init(){
read(n), read(k);
ans = 0, lg[1] = 1;
for(int i = 2; i <= k; ++i) lg[i] = (lg[i - 1] * 71) % MAX;
hash[0].push_back(0); //要对第一个人就符合条件进行判断
}
int main(){
init();
for(int i = 1; i <= n; ++i){
read(num);
for(int j = 1; j <= k; ++j, num >>= 1) //进行数字分解并进行前缀和计算
sum[i][j] = sum[i - 1][j] + (num & 1), a[i][j] = sum[i][j] - sum[i][1]; // 计算相对差值
HASH(i);
}
printf("%d\n", ans);
return 0;
}