[LuoguP1360][USACP07MAR]黄金阵容均衡(Link)
每天会增加一个数\(A\),将\(A\)二进制分解为\(a[i]\),对于每一个\(i\)都增加\(a[i]\),如果一段时间之内所有的位数上的数都增加了同一个数,那么成这个天数区间为均衡的。现在要求最长的均衡区间。
这道题很显然可以使用前缀和。我们统计每一天的前缀和为一个\(map\)数组\(A\)。如果区间\([L, R]\)为均衡区间,那么\(A[R] - A[L - 1]\)就一定满足每一个二进制分解的位数都相等。那么我们不妨设一个起始点数组,一个结束点数组。也就是\(L[i]\)和\(R[i]\),那么肯定有\(R[i] - L[i] = 0\)。也就是\(R[1] - L[1] = R[2] - L[1] =..= R[N] - L[N]\) 。那么我们进而可以知道\(R[i] - R[j] = L[i] - L[j]\)。
进而我们看到只要每一次计算前缀和后减去第一位的值相等,那么就是一个均衡区间。于是我就\(yy\)出一种类似于哈希的做法。首先定义每天的状态以及每一种状态对应那一天。然后每次读到一个数,判断现在的状态是否在之前出现过,如果出现过,那么就可以\(Ans = max(Ans, i - F[A])\),其中\(i - F[A]\)就是当前天数减去当前状态\(A\)对应的之前的天数,然后取个\(max\)就可以了。
可以使用\(map\)记录状态。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <vector>
#include <map>
#include <algorithm>
using namespace std ;
typedef long long LL ;
const int MAXN = 10010 ;
const int MAXM = 10010 ;
const int Inf = 0x7fffffff ;
LL N, M, Ans ;
map <vector <int>, int> F ;
inline LL Read() {
LL X = 0, F = 1 ; char ch = getchar() ;
while (ch > '9' || ch < '0') F = (ch == '-' ? - 1 : 1), ch = getchar() ;
while (ch >= '0' && ch <= '9') X=(X<<1)+(X<<3)+(ch^48), ch = getchar() ;
return X * F ;
}
int main() {
freopen("in.in", "r", stdin) ;
N = Read(), M = Read() ;
vector <int> A(M);
for (int i = 1 ; i <= N ; i ++) {
LL X = Read() ;
for (int j = 0 ; j < M ; j ++)
A[j] += (X & (1 << j)) ? 1 : 0 ;
if (X & 1) for (int j = 0 ; j < M ; j ++) A[j] -- ;
if (F.count(A)) Ans = max(Ans, LL(i) - F[A]) ;
else F[A] = i ;
} printf("%lld", Ans) ; return 0 ;
}