源地址:http://poj.org/problem?id=3274
题目大意就是给你N头牛,然后给你一个特征值,比如6的二进制表示是110,说明这头牛有第二个和第三个特征,而没有第一个特征,现在题中会给一个k,表示一共有的特征数,让求一个最大的范围i~j,使得在这i~j头牛中k个特征出现的次数相同。
看了别人的思路才知道这道题目的解法。
首先,我们设一个数组sum[i][j],表示前i头牛中j特征出现的次数,那么如果想要一个区间内k个特征出现的次数相同,那么 sum[i][0]-sum[j][0] = sum[i][1] -sum[j][1] = sum[i][2] - sum[j][2] =....=sum[i][k-1]-sum[j][k-1] 其中最大的i-j就是答案。
通过变换式子,我们可以得到如下的新式子。
sum[i][1] - sum[i][0] = sum[j][1] - sum[j][0]
sum[i][2] - sum[i][0] = sum[j][2] - sum[j][0]
sum[i][3] - sum[i][0] = sum[j][3] - sum[j][0]
.....................
那么我们再设一个数组c[i][j] = sum[i][j] - sum[i][0] (j<k),则题中要求的便化为了 c[i][] = c[j][]中最大的i-j范围
比如题中数据
7 3
7 6 7 2 1 4 2
它的sum矩阵是
1 1 1
1 2 2
2 3 3
2 4 3
3 4 3
3 4 4
3 5 4
它的c矩阵是
0 0 0
0 0 0
0 1 1
0 1 1
0 2 1
0 1 0
0 1 1
0 2 1
它的第2行和第6行是相同的,所以答案为6-2=4
注意!c矩阵是有个0行的,全为0,这个一定要有,也就是说刚开始的时候k种特征出现的次数都一样,都为0.如果后面出现了全为0的一行,就得和这一行对起来。
而题目中数据很大,不能一一枚举c矩阵,那么我们就用哈希的方法来寻找,这和3349差不多。
#include<stdio.h>
#include<iostream>
#include<string>
#include<string.h>
#include<algorithm>
#include<iomanip>
#include<vector>
#include<time.h>
#include<queue>
#include<stack>
#include<iterator>
#include<math.h>
#include<stdlib.h>
#include<limits.h>
#include<map>
//#define ONLINE_JUDGE
#define eps 1e-8
#define INF 0x7fffffff
#define FOR(i,a) for((i)=0;i<(a);(i)++)
#define MEM(a) (memset((a),0,sizeof(a)))
#define sfs(a) scanf("%s",a)
#define sf(a) scanf("%d",&a)
#define sfI(a) scanf("%I64d",&a)
#define pf(a) printf("%d\n",a)
#define pfI(a) printf("%I64d\n",a)
#define pfs(a) printf("%s\n",a)
#define sfd(a,b) scanf("%d%d",&a,&b)
#define sft(a,b,c)scanf("%d%d%d",&a,&b,&c)
#define for1(i,a,b) for(int i=(a);i<b;i++)
#define for2(i,a,b) for(int i=(a);i<=b;i++)
#define for3(i,a,b)for(int i=(b);i>=a;i--)
#define MEM1(a) memset(a,0,sizeof(a))
#define MEM2(a) memset(a,-1,sizeof(a))
const double PI=acos(-1.0);
template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}
template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}
template<class T> inline T Min(T a,T b){return a<b?a:b;}
template<class T> inline T Max(T a,T b){return a>b?a:b;}
using namespace std;
#define ll __int64
int n,m;
#define Mod 1000000007
#define N 110
#define M 1000100
const int prime=999983;
int sum[M][35]; //sum[i][j]表示前i头牛的j特征的数量
int c[M][35]; //c[i][j] = sum[i][j] - sum[i][0]
int feature[M][35];
int k;
int len;
struct Hashtable{
int row;
Hashtable*next;
Hashtable(){
next = 0;
}
};
Hashtable *hash[prime+5];
int getKey(int p){
int key = 0;
for(int j=0;j<k;j++)
key += (c[p][j]*j);
key = abs(key)%prime; //哈希值有可能是负的,得取正
return key;
}
bool cmp(int p1,int p2){
for(int j=0;j<k;j++)
if(c[p1][j] != c[p2][j])
return false;
return true;
}
void insert(int p){
int key = getKey(p);
if(!hash[key]){
Hashtable *tmp = new Hashtable;
tmp->row = p;
hash[key] = tmp;
}else{
Hashtable *tmp = hash[key];
if(cmp(tmp->row,p)){
if(p-tmp->row>len)
len = p-tmp->row;
return;
}
while(tmp->next){
tmp = tmp->next;
if(cmp(tmp->row,p)){
if(p-tmp->row>len)
len = p-tmp->row;
return;
}
}
tmp->next = new Hashtable;
tmp->next->row = p;
}
return;
}
int main(){
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
// freopen("out.txt","w",stdout);
#endif
while(sfd(n,k)!=EOF){
for(int i=0;i<k;i++){ //初始化,即前0头牛具有的特征均为0
sum[0][i] = 0;
c[0][i] = 0;
}
int x;
memset(hash,0,sizeof hash);
insert(0); //要放入第0头牛!
len = 0;
for(int i=1;i<=n;i++){
scanf("%d",&x);
for(int j=0;j<k;j++){
feature[i][j] = x%2; //存储第i只牛是否具有j特征
x /= 2;
sum[i][j] = sum[i-1][j]+feature[i][j];
c[i][j] = sum[i][j] - sum[i][0];
}
insert(i);
}
printf("%d\n",len);
// for(int i=1;i<=n;i++){
// for(int j=0;j<k;j++)
// printf("%d ",sum[i][j]);
// printf("\n");
// }
// puts("");
// for(int i=0;i<=n;i++){
// for(int j=0;j<k;j++)
// printf("%d ",c[i][j]);
// printf("\n");
// }
}
return 0;
}