Codevs 1247 排排站
题目描述 Description
FJ的N头奶牛有一些共同之处(1 <= N <= 100,000)。FJ可以将这N头奶牛通过K种特征来归类(1 <= K <= 30)。例如,一些奶牛表现出来的特征1可能是有斑点,特征2可能是较之于PASCAL更喜欢C,等等。
FJ发明了一种简明的描述特征的方法——“特征码”,用一个长度为k的二进制串来表示这头牛的特征表现。例如,一头牛的“特征码”为13,转换为二进制就是1101,代表这头牛具有特征1、3、4 (从右读到左),但是不表现特征2。总的说来,如果这头奶牛表现特征i,那么我们在他的“特征码”的二进制的第i位就为1。
FJ将奶牛排成了一个1..N的队列,他注意到一种确定的排列方法可以使奶牛们的表现更“平衡”。一个连续的i..j的范围平衡表示为如果K种特征都有同样多的奶牛来表现。FJ想知道他究竟可以排出一个多长的“平衡”队列。请帮助他。
输入描述 Input Description
第一行两个整数n和k
接下来n行每行一个整数
输出描述 Output Description
一个整数表示最大的长度
样例输入 Sample Input
7 3
7
6
7
2
1
4
2
样例输出 Sample Output
4
/* 暴力,将所有特征数字转换为二进制后,存到a[][]数组里,然后竖着看,从每一头牛往下数,找以这头牛为起点的最大长度,这个暴力其实不用hash */ #include<iostream> #include<cstdio> #include<cstring> #define maxn 100010 #define mod 12200717 int n,m,a[maxn][40],h[maxn][40],ans; using namespace std; void change(int x){ int z=1<<(m-1),y=a[x][0]; for(int i=1;i<=m;i++){ if(y-z>=0)y-=z,a[x][i]=1; else a[x][i]=0; z>>=1; } } void hash(int from,int len,int num){ h[from][num]+=a[from+len-1][num]; } int main(){ freopen("Cola.txt","r",stdin); scanf("%d%d",&n,&m); for(int i=1;i<=n;i++){ scanf("%d",&a[i][0]); change(i); } int now=0; for(int i=1;i<=n;i++){//起点 if(n-i+1<=ans)break; for(int j=1;j<=n-i+1;j++){//长度 int len=j; bool flag=0; hash(i,j,1); int st=h[i][1]; for(int k=2;k<=m;k++){//每头牛的信息 hash(i,j,k); if(h[i][k]!=h[i][1]){ flag=1; } } if(flag==0)ans=max(ans,len); } } printf("%d",ans); }
/* 还是差分 因为对于符合条件的序列 有 sj0 - si0 = sj1 - si1 =...= sjk-1 - sik-1 也就是说 如果存在i j 满足 sj1 - sj0 == si1 - si0 sj2 - sj0 == si2 - si0 ...... sjk-1 - sj0 == sik-1 - si0 我们定义c[i,j]=s[i,j]-s[i,0] 问题就转化成了 找隔得最远的ij 满足c[i] 和 c[j] 一样 这里用hash加速查找 给每个c[i] 搞一个hash值 放到hash表里 坑死我了,if(r<0) r=-r,查错查了一个小时 */ #include<iostream> #include<cstdio> #include<cstring> using namespace std; #define mod 1000003 int n,m,a[100010],sum[100010][50],b[100010][50],h[1000100],ans; int hash(int x){ int r=0; for(int i=1;i<=m;i++)r=r%mod+b[x][i]<<2; if(r<0)r=-r; return r%mod; } int main(){ scanf("%d%d",&n,&m); int x; for(int i=1;i<=n;i++)scanf("%d",&a[i]); for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if((1<<(j-1))&a[i])sum[i][j]=sum[i-1][j]+1; else sum[i][j]=sum[i-1][j]; for(int i=1;i<=n;i++){ for(int j=1;j<=m;j++){ b[i][j]=sum[i][j]-sum[i][1]; } } memset(h,-1,sizeof(h)); h[0]=0; for(int i=1;i<=n;i++){ int k=hash(i); while(h[k]!=-1){ int flag=0; for(int j=1;j<=m;j++){ if(b[h[k]][j]!=b[i][j]){flag=1;break;} } if(flag==0&&i-h[k]>ans){ans=i-h[k];break;} k++; } if(h[k]==-1)h[k]=i; } printf("%d",ans); }