Farmer John's N cows (1 ≤ N ≤ 100,000) share many similarities. In fact, FJ has been able to narrow down the list of features shared by his cows to a list of only K different features (1 ≤ K ≤ 30). For example, cows exhibiting feature #1 might have spots, cows exhibiting feature #2 might prefer C to Pascal, and so on.
FJ has even devised a concise way to describe each cow in terms of its "feature ID", a single K-bit integer whose binary representation tells us the set of features exhibited by the cow. As an example, suppose a cow has feature ID = 13. Since 13 written in binary is 1101, this means our cow exhibits features 1, 3, and 4 (reading right to left), but not feature 2. More generally, we find a 1 in the 2^(i-1) place if a cow exhibits feature i.
Always the sensitive fellow, FJ lined up cows 1..N in a long row and noticed that certain ranges of cows are somewhat "balanced" in terms of the features the exhibit. A contiguous range of cows i..j is balanced if each of the K possible features is exhibited by the same number of cows in the range. FJ is curious as to the size of the largest balanced range of cows. See if you can determine it.
Input
Lines 2.. N+1: Line i+1 contains a single K-bit integer specifying the features present in cow i. The least-significant bit of this integer is 1 if the cow exhibits feature #1, and the most-significant bit is 1 if the cow exhibits feature # K.
Output
感想:
本来以为是dp,一次tle才发现N*N有点问题,改成hash之后这个函数并不太好,但是有负数,稍后再去找个分布更好的函数吧
文章翻译:
农民约翰的要去展会的N头牛(1≤N≤100000)有许多相似之处。事实上,约翰给牛列出K种不同特性(1≤K≤30)并制表。例如,牛# 1可能有斑点,牛# 2可能更喜欢C ,等等。先进又无聊的农夫甚至设计了一种简明的方式--特性ID来描述每个牛.ID是一个K-bit整数的二进制,表示告诉我们展出的牛的特性。作为一个例子,假设一个牛特性ID = 13。因为1101=13,这意味着我们的牛展品有特性1、3和4(阅读右到左),而不是特性2,作为一个没事儿秀智商的农夫,约翰把牛赋予序号从1-N排序,而且发现牛的特性在某个区间内是平衡的,(平衡的,展示每个特征的牛总数相同.)约翰好奇最大的平衡区间长度,请你找出它
输入
第一行 N: 总牛数 K: 总特征数
第二行到N+1行 第i行代表第i-1号牛的特征ID
输出
一行 最大平衡区间长度+换行
题目理解:
1 阅读从哪个方向都一样
2 设区间[i,j],按位相加压缩成一行k,对单一行,当其他特征相对于第一个特征为0时,所有特征这一行满足条件
3 设区间[i,j],令memo[i][0]=0,memo[i][ki]为第ki个特征相对于第一个特征的积累值,若memo[i]=memo[j],那么区间[i+1,j]满足平衡,平衡长度为i-j
//13080K 610MS
#include <iostream>
#include<cstdlib>
#include <cstring>
using namespace std;
const int MAXF =30;
const int MAXN=100005;
const int MAXK=(1<<14);
int memo[MAXN][MAXF];//权值储存在memo里
int first[MAXK];//采用邻接表形式存储,也即存储关系R {<x,y>|<first[i],j>,<j,next[j]> i是键值.j则为牛的序号}
int next[MAXN];//下一条
int num[MAXK];//方便对每个键值对应的边权查重,存储对应键值加入了多少
bool vis[MAXN];//是否已经查重完毕,因为关系<next[i],i>没有重复所以不用memset,否则反而败笔
int n,k;
#define CONJECTURE(n) if(n) {cout<<"ERROR"<<endl;exit(-1);}//
bool cmp(int a,int b){//边权查重
for(int i=0;i<k;i++){
if(memo[a][i]!=memo[b][i])return false;
}
return true;
}
int ckey(int i){//键值分配
int ans=0;
for(int j=0;j<k;j++){
ans+=memo[i][j];
}
ans=ans>=0?ans:-ans;//错误一次,有负值,没有改动整个函数只是改为绝对值
ans%=MAXK;
return ans;
}
int main(){
ios::sync_with_stdio(false);
//一:输入
cin>>n>>k;
int temp;
// if(k==1){cout<<n<<endl;return 0;}
//bool fl=false;//有没有都可以..加入了第0行:000000...00,这意味着存在完全状态也会检出
// if(temp==(1<<k)-1)fl=true;
cin>>temp;
for(int j=1;j<k;j++){
memo[1][j]=((temp&(1<<j))>>j)-(temp&1);
}
for(int i=2;i<=n;i++){
int temp;
cin>>temp;
// if(temp==(1<<k)-1)fl=true;
for(int j=1;j<k;j++){
memo[i][j]=memo[i-1][j]+((temp&(1<<j))>>j)-(temp&1);//错误一次,忘记了temp&(1<<j)不是1
}
}
memset(first,-1,sizeof(first));//加入了<0,0>点,所以起点定-1
memset(next,-1,sizeof(next));
//二:添加边
for(int i=0;i<=n;i++){
int keynum=ckey(i);
if(first[keynum]!=-1){
next[i]=first[keynum];
}
first[keynum]=i;
num[keynum]++;
}
//三:比较
int ans=0;
int minn,maxn;
for(int i=0;i<MAXK;i++){
int start;
while(num[i]){
int p=first[i];
//bool fl=false;
while(p!=-1){
if(!vis[p]){
start=p;
// fl=true;
break;
}
p=next[p];
}
minn=maxn=start;
vis[start]=true;
num[i]--;
while(next[p]!=-1){
p=next[p];
if(vis[p])continue;
if(cmp(start,p)){
minn=p;
vis[p]=true;
num[i]--;
}
}
ans=max(maxn-minn,ans);
}
}
//四:输出
cout<<ans<<endl;
return 0;
}