poj3274 Gold Balanced Lineup

Gold Balanced Lineup
Time Limit: 2000MS Memory Limit: 65536K
Total Submissions: 14458 Accepted: 4192

Description

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

Line 1: Two space-separated integers,  N and  K
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

Line 1: A single integer giving the size of the largest contiguous balanced group of cows.

Sample Input

7 3
7
6
7
2
1
4
2

Sample Output

4

Hint

In the range from cow #3 to cow #6 (of size 4), each feature appears in exactly 2 cows in this range

这个题的意思就是


比我自己说要明白多了呢,我表示读英语的时候完全没有读出这个意思啊喂!(╯‵□′)╯︵┻━┻。

这个题的意思就是如果把每头牛转化成2进制的数,那么要求的应该是 一个最大区间,这个区间满足 (2进制)1-K上的每一位出现的1的次数和相同。

我们可以借助前缀和数组,先把牛们都转化成2进制,然后做一个累加和,像这样:

数字  特征值    第几头牛

   7          1 1 1                1

   6          0 1 1                2

   7          1 1 1                3

   2          0 1 0                4

   1          1 0 0                5

   4          0 0 1                6

   2          0 1 0                7

按行累加得:

               1 1 1

               1 2 2

               2 3 3

               2 4 3

               3 4 3

               3 4 4

               3 5 4

试想一下,在某个区间内每一位上出现的1的次数的和相同,应当满足什么条件?

我们设第i行的序列为a[1],a[2],a[3],a[4].....,a[k]第j行上的序列为b[1],b[2],b[3],b[4]...b[k]

那么我们应当满足a[1]-b[1]=a[2]-b[2]=a[3]-b[3]=a[4]-b[4]=......a[k]-b[k],怎么样,是不是忽然醒悟了,满足这个条件就表明,在i+1~j这个区间内,是满足条件的。

然后我们把这个式子转化一下,我们就应当满足a[1]-a[k]=b[1]-b[k],a[2]-a[k]=b[2]-b[k],a[3]-a[k]=b[3]-b[k]......

所以我们就可以转化一下,把每个前缀和数列都减去a[k](减去哪个都是可以的,只要是同一个)

之后只要满足这两个数列完全一样就可以了。像这样:

(我后面是从后面倒着来的序列,实质上都是一样哒)

都减去第一列得:

0 0 0

0 1 1

0 1 1

0 2 1

0 1 0

0 1 1

0 2 1

所以说  最大区间是  6-2 = 4.

寻找相同数列的时候,可以参照我的上一篇博客里面的,按照和来哈希寻找,每创造一个新的前缀和数列,就去自己的哈希表中查找,如果有相同的更新答案的最大值,这里没必要再压入哈希表,因为是按照顺序来的,所以只保留上界的数列就可以。

这里有一个比较奇特的方法,老实说不知道和哈希比谁更快)如果只是比较数列相同,那么我们可以把数列按照每一位排序,之后再逐一比较,排好序之后,初始化上界和下界为0,之后如果相同就更新下界,否则,便用下界减去上界,更新答案最大值,并且此时更新上界下界。



这里还有一个非常特殊的情况,那就是出现全为0的情况,(我如果不去看人家怎么做的,估计我一天都不知道哪里错了QAQ)!!!

像这样:

0 1 2 1 1 0 2

0 0 0 2 1 1 1

0 0 0 0 0 0 0 

因此我们在第0行加上一行0;

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <algorithm>
#include <cmath>
#include <vector>
#include <map>
using namespace std;
const int MAXN=100000+5;
const int inf=0x3f3f3f;
int n,k;
struct node
{
    int p[32];
    int num;
    bool operator<(const node &a)const
    {
        for(int i=0;i<k;++i)//这里是排序,按照每一位从小到大
        {
            if(a.p[i]!=p[i])
            {
                return a.p[i]>p[i];
            }
        }
        return a.num>num;//如果每一位都相同,按照行号从小到大排
    }
    bool operator ==(const node &a)const//判断相等
    {
        for(int i=0;i<k;++i)
        {
            if(a.p[i]!=p[i])return 0;
        }
        return 1;
    }
}a[MAXN];

int main()
{
    scanf("%d%d",&n,&k);
    int i,j;
    int x;
    for(j=0;j<k;++j)a[0].p[j]=0;//添加“0”行
    a[0].num=0;
    for(i=1;i<=n;++i)
    {
        scanf("%d",&x);
        a[i].num=i;
        for(j=0;j<k;++j)
        {
            a[i].p[j]=x&1;
            a[i].p[j]+=a[i-1].p[j];//从第二行直接累加和
            x>>=1;
        }

        int d=a[i].p[0];                 //都减去第一列
        for(j=0;j<k;++j)a[i].p[j]-=d;
    }
    sort(a,a+n+1);//排序
    /*for(i=0;i<n;++i)
    {
        for(j=0;j<k;++j)printf("%d ",a[i].p[j]);                     //这里你可以自己看一看排序好的数列情况
        printf("\n%d\n",a[i].num);
    }*/
    int ans=0;
    int b=0,e=0;//初始化上下界
    for(i=1;i<=n;++i)
    {
        if(a[i]==a[i-1])//相等更新下界
        {
            e=i;
        }
        else
        {
            ans=max(ans,a[e].num-a[b].num);//不相等更新答案,并且更新上下界
            b=i;
            e=i;
        }
    }
    ans=max(ans,a[e].num-a[b].num);
    printf("%d\n",ans);
    return 0;
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值