P1360 [USACO07MAR]Gold Balanced Lineup G(前缀和&Hash)

瓶颈之处在于:如何快速判断一个区间的m种能力和相等。

显然可以预处理所有能力的前缀和。

区间满足的条件是 m m m种能力的前缀和之差都相同。

p r e R pre_R preR的所有能力减去一个相同的值,等于 p r e L − 1 pre_{L-1} preL1

因此这两个前缀和在某种意义上等价的。

因此我们尝试找到一个基准值,比如以第一个能力为基准,我们始终都让第一个能力为0,当不为0时我们就进行所有能力减1的操作,这样我们就能保证两个前缀和具有相同的值。

然后我们就可以hash或者map来储存这个形式的前缀和数组,取最值即可、

code

// Problem: P1360 [USACO07MAR]Gold Balanced Lineup G
// Contest: Luogu
// URL: https://www.luogu.com.cn/problem/P1360
// Memory Limit: 125 MB
// Time Limit: 1000 ms
// Date: 2021-07-03 10:18:20
// --------by Herio--------

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef unsigned long long ull; 
const int N=1e3+5,M=2e4+5,inf=0x3f3f3f3f,mod=1e9+7;
#define mst(a,b) memset(a,b,sizeof a)
#define PII pair<int,int>
#define fi first
#define se second
#define pb emplace_back
#define SZ(a) (int)a.size()
#define IOS ios::sync_with_stdio(false),cin.tie(0) 
void Print(int *a,int n){
	for(int i=1;i<n;i++)
		printf("%d ",a[i]);
	printf("%d\n",a[n]); 
}
map<ull,int>mp;
int n,m,ans;
vector<int>a;
int base=131;
ull Hash(){
	ull h[33]={};
	for(int i=0;i<m;i++)
		h[i+1]=h[i]*base+a[i];
	return h[m];
}
int main(){
	scanf("%d%d",&n,&m);a.resize(m);
	mp[Hash()]=0;
	for(int i=1;i<=n;i++){
		int x;scanf("%d",&x);
		for(int j=0;j<m;j++)
			if(x>>j&1) a[j]++;
		if(x&1) for(int j=0;j<m;j++) a[j]--;
		ull y=Hash();
		if(mp.count(y)) ans=max(ans,i-mp[y]);
		else mp[y]=i;
	}
	printf("%d\n",ans);
	return 0;
}