Codevs 1247 排排站

1247 排排站

 

USACO

 时间限制: 1 s
 空间限制: 128000 KB
 题目等级 : 钻石 Diamond
 
 
 
题目描述 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 






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);
}
40分 超时
/*
还是差分
因为对于符合条件的序列
有 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);
}
100分
原文地址:https://www.cnblogs.com/thmyl/p/7192867.html