题意:FJ 有N头牛,N最多是10^5 ,每头牛最多有30种特征,一头牛所具有的特征可以用一个数来表示,将这个数化成2进制,第i位上权为1,说明它具有第i种特征,如果有一个区间(牛编号连续),使得这个区间的牛的每种特征之和相等,则这个区间为平衡区间。现在告诉你牛的个数n,特征个数k和每头牛的特征值,让你求最大的平衡区间。
分析转自:here:
这个题目的转化有点困难,看了别人的报告才明白是怎么回事。
给出SAMPLE
7 3
7
6
7
2
1
4
2
先转化成二进制:
1 1 1
1 1 0
1 1 1
0 1 0
0 0 1
1 0 0
0 1 0
然后在列上进行累加:
1 1 1
2 2 1<----
3 3 2
3 4 2
3 4 3
4 4 3<----
4 5 3
上面这两步转化还好想。答案是4,是因为两个箭头所指的行列上的差相等。
然后在行上,所有值减去最右边的数:
0 0 0
1 1 0<----
1 1 0
1 2 0
0 1 0
1 1 0<----
1 2 0
这一步转化推一下就知道,不过实在不好想。
然后找出两个一样的行,使他们的距离最远。答案就是最远的距离。
Code(方法一):
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <map>
#include <set>
#define eps 1e-7
#define LL long long
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int maxn=100005;
int k;
struct node{
int d[33],id;
bool operator <(const node &a)const {
for(int i=k-1;i>=0;i--) if(d[i]!=a.d[i])
return d[i]<a.d[i];
return id<a.id;
}
bool operator == (const node &a)const {
for(int i=k-1;i>=0;i--) if(d[i]!=a.d[i])
return false;
return true;
}
}List[maxn];
int main()
{
int n,x;
scanf("%d %d",&n,&k);
if(n==1){
printf("1\n");
return 0;
}
memset(List,0,sizeof(List));
for(int i=1;i<=n;i++){
scanf("%d",&x);
List[i].id=i;
for(int j=0;j<k;j++){
List[i].d[j]=(x&1)+List[i-1].d[j];
x>>=1;
}
}
for(int i=1;i<=n;i++){
for(int j=1;j<k;j++)
List[i].d[j]-=List[i].d[0];
List[i].d[0]=0;
}
sort(List,List+1+n);
List[n+1].d[0]=-0x3f3f3f3f;
int i=0,j=0,ans=0;
while(i<=n){
while(List[i]==List[j]) j++;
ans=Max(ans,List[j-1].id-List[i].id);
i=j;
}
printf("%d\n",ans);
return 0;
}
Code(方法二hash):
#include <algorithm>
#include <iostream>
#include <cstring>
#include <string>
#include <cstdio>
#include <vector>
#include <queue>
#include <cmath>
#include <map>
#include <set>
#define eps 1e-7
#define LL long long
#define pb push_back
#define lson l,m,rt<<1
#define rson m+1,r,rt<<1|1
#define Max(a,b) ((a)>(b)?(a):(b))
#define Min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int maxn=100005;
const int HASH=100003;
int n,k;
int bit[maxn][33],head[HASH],Next[HASH];
int get_hash(int v[]){
int h=0;
for(int i=0;i<k;i++) h=(h<<2)+(v[i]>>4)^(v[i]<<10);
h%=HASH;
h=h<0?h+HASH:h;
return h;
}
bool issame(int x[],int y[]){
for(int i=0;i<k;i++) if(x[i]!=y[i])
return false;
return true;
}
int main()
{
scanf("%d %d",&n,&k);
memset(bit[0],0,sizeof(bit[0]));
memset(head,-1,sizeof(head));
int x,ans=0;
for(int i=1;i<=n;i++){
scanf("%d",&x);
for(int j=0;j<k;j++) {
bit[i][j]=bit[i-1][j]+(x&1);
x>>=1;
}
}
for(int i=0;i<=n;i++){
for(int j=1;j<k;j++) bit[i][j]-=bit[i][0];
bit[i][0]=0;
int tmp=get_hash(bit[i]);
for(int id=head[tmp];id!=-1;id=Next[id]){
if(issame(bit[i],bit[id])){
ans=Max(ans,i-id);
}
}
Next[i]=head[tmp];
head[tmp]=i;
}
printf("%d\n",ans);
return 0;
}