poj 3274 Gold Balanced Lineup

本文介绍了一种解决特定问题的高效算法,旨在找到一组奶牛中,不同特性分布均匀的最大区间。通过二进制转换和哈希技术,实现算法优化,避免了传统方法的超时问题。
题目的意思是有n只奶牛,k种特性,每个奶牛有一个数值,转换成二进制数第i位为0表示没有第i种特性
为1表示有。求一个最大的范围,使得该范围内每种特性出现的次数都一样
做法,先转换成二进制
然后累加,d[k][i]表示1到k只奶牛有i特性的奶牛一共有多少只
若d[i][k]-d[j][k]对于所有的k都相等,则表示i+1到j这一段的奶牛满足条件。
但是现在枚举的复杂度在n*n,超时
再思考下,可以做如下变换
对于d[i][]的每一位,都减去最小的一位。做这个转化是为了简化判断
现在的判定变成了d[i][k]==d[j][k]对于所有的k都满足
到了这一步
相信有哈希基础的朋友都能想到o(nk)的做法了
把每个d[k]做一次哈希。
我采取的哈希办法为每个值累加。
解决碰撞的方法用的是数组模拟链表。
#include
#include
#include
using namespace std;
const int maxn=111111,inf=9999999;
int d[maxn][32],a[maxn];
int ans;
int n,m;
int lon;
struct
{
    int tmp[32];
    int next,key;
}hash[311111];

int gethash(int d[])
{
    int txt=d[1];
    for(int i=2;i<=m;i++)
    txt+=d[i];
    txt%=maxn;
    return(txt);
}

int check(int d[],int k)
{
    int txt=gethash(d);

//    printf("%d %d\n",txt,k);

    while(hash[txt].key!=-1)
    {
        int ture=1;
        for(int i=1;i<=m;i++)
        if(d[i]!=hash[txt].tmp[i])
        {
            ture=0;
            break;
        }
        if(ture)
        {
//            printf("%d %d\n",k,hash[txt].key);
            ans=ans>(k-hash[txt].key)?ans:(k-hash[txt].key);
            return(0);
        }
        txt=hash[txt].next;
    }
    for(int i=1;i<=m;i++)
    hash[txt].tmp[i]=d[i];
    hash[txt].key=k;
    hash[txt].next=++lon;
}


int main()
{
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)
        scanf("%d",&a[i]);
        for(int k=1;k<=n;k++)
        {
            for(int i=1;i<=m;i++)
            {
                d[k][i]=a[k]%2;
                a[k]>>=1;
            }
        }
        for(int k=2;k<=n;k++)
        for(int i=1;i<=m;i++)
        d[k][i]+=d[k-1][i];

        for(int k=1;k<=n;k++)
        {
            int txt=inf;
            for(int i=1;i<=m;i++)
            txt=txt
            for(int i=1;i<=m;i++)
            d[k][i]-=txt;
        }
        ans=0;
        lon=maxn;
        memset(hash,-1,sizeof(hash));
        int tr[32];
        memset(tr,0,sizeof(tr));
        check(tr,0);
        for(int k=1;k<=n;k++)
        {
            check(d[k],k);
        }
        printf("%d\n",ans);
//        for(int k=1;k<=n;k++)
//        {
//            for(int i=1;i<=m;i++)
//            printf("%d ",d[k][i]);
//            printf("\n");
//        }
    }

}

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值