poj-3274

#include <stdio.h>
#include <string.h>

const int COW_MAX = 100000;
const int K_MAX = 31;

int cowSumInfo[100000][32];

#define BIG_PRIME 100003

struct C {
    int CInfo[32];
    char used;
    int hval;
    int cow_sequence;
};

typedef struct C C;

C CHashArray[100010];

int hash(int * CArray, int length) {
    long long powSum = 0;
    int i = 1;
    for (; i < length; i++) {
        powSum += CArray[i] * CArray[i];
    }
    return powSum % BIG_PRIME;
}

char CEqual(int * CArray1, int * CArray2, int length) {
    int i = 1;
    for (; i < length; i++) {
        if (CArray1[i] != CArray2[i]) {
            return 0;
        }
    }
    return 1;
}

int fillAndGetRangeLength(int * CArray, int length, int cow_sequence) {
    int hval = hash(CArray, length);
    int insertPos = hval;
    int arraySize = length * sizeof (int);
    int longestRange = 0;

    while(1) {
        if (!CHashArray[insertPos].used) {
            CHashArray[insertPos].cow_sequence = cow_sequence;
            CHashArray[insertPos].hval = hval;
            CHashArray[insertPos].used = 1;
            memcpy(CHashArray[insertPos].CInfo, CArray, arraySize);
        } else {
            if (CHashArray[insertPos].hval == hval) {
                if (CEqual(CArray, CHashArray[insertPos].CInfo, length)) {
                    return cow_sequence - CHashArray[insertPos].cow_sequence;
                }
            }
            if (++insertPos >= BIG_PRIME + 1) {
                insertPos = 0;
            }
        }
    }
}

int checkLongest(int cow_num, int K) {
    int longest = 0;
    int C[32] = {0};
    fillAndGetRangeLength(C, K, 0);
    int i = 1;
    for (; i <= cow_num; i++) {
        int j = 1;
        int rangeLength = 0;
        C[0] = 0;
        for (; j < K; j++) {
            C[j] = cowSumInfo[i][j] - cowSumInfo[i][0];
            // printf("%d ", C[j]);
        }
        // printf("\n");
        rangeLength = fillAndGetRangeLength(C, K, i);
        longest = longest >= rangeLength ? longest : rangeLength;
    }
    printf("%d\n", longest);
    return longest;
}

void buildcowSumInfo(int cow_sequence, int cow_feature, int K) {
    int cur_feature = 1;
    int i = 0;
    for (; i < K; i++) {
        int increment = 0;
        if (cur_feature & cow_feature) {
            if (!cow_sequence) {
                cowSumInfo[cow_sequence][i]++;
            } else {
                cowSumInfo[cow_sequence][i] = cowSumInfo[cow_sequence-1][i] + 1;
            }
        } else {
            if (!cow_sequence) {
                cowSumInfo[cow_sequence][i] = 0;
            } else {
                cowSumInfo[cow_sequence][i] = cowSumInfo[cow_sequence-1][i];
            }
        }
        cur_feature = cur_feature<<1;
    }

    // for (int i = 0; i < K; i++) {
    //     printf("%d ", cowSumInfo[cow_sequence][i]);
    // }
    // printf("\n");
}

int main() {
    int K;
    int cow_num;
    while(scanf("%d", &cow_num) > 0) {
        int i = 0;
        scanf("%d", &K);
        memset(CHashArray, 0, sizeof(CHashArray));
        memset(cowSumInfo, 0, sizeof(cowSumInfo));
        for (;i < cow_num; i++) {
            int cow_feature;
            scanf("%d", &cow_feature);
            buildcowSumInfo(i+1, cow_feature, K);
        }

        checkLongest(cow_num, K);
    }

}

C++(GCC WA.....)  26384K 532MS

这道题的难点其实已经不在hash了, 而是如何转化的问题, 刚开始看题,没都懂,后来查了查才清楚:

一个人养了N头牛, 而牛们则一共有K种特性: 每种有自己的编号, 比如feature1 就是牛身上有斑点, feature2就是牛更喜欢pascal(尼玛, 黑程序员...),

每头牛的特性总和可以用一个数来表示: 比如 7 = 0111(二进制), 那么这头牛就有特性 1 ,2 ,3 (跟二进制每一位有关).

题目让求的其实就是在这一群牛里, 从第i 牛 到 第 j 牛中,拥有每种特性的牛的数量都是一样的:

一个例子:

7 3

7 (111)

6 (110)

7 (111)

2 (010)

1 (001)

4 (100)

2 (010)

一共7头牛,共3种特性, 那么可以看到 从第3头牛 到 第6头牛, 分别拥有这3种特性的牛的数量是相等的(都是2)。

这就是一个黄金平衡牛群,要找的就是最大的黄金平衡牛群,输出其大小即可(这个例子就是 4,  从3~ 6共4头).


接下来就是如何转化成程序可以搞定的问题了, 貌似这道题还是一道经典题,很多兄弟也都直接参考了官方解题报告:

先这样定义一个数据:sum[i][k] :  从开始到第i头牛,拥有特性k 的牛的数量总和:

那么题目要求的牛群(i~j, 共K种特性)就满足这样的条件:

sum[j][1] - sum[i-1][1] == sum[j][2] - sum[i-1][2] == .... == sum[j][K] - sum[i-1][K], 即对于每种特性, 第 j头到第i头牛中, 拥有此特性的牛的数量都相等.

注意是i-1 而不是 i(因为牛群把第i头算进去了, 因此要比较, 必须与i-1比较)


这个数组很好得到, 不过有个比较关键的一点是, 对于sum[0][k] 要置为0(0头牛,自然特性数都是0), sum数组的第一组数据应该是全0, 当时漏了这个考虑.

这种情况就出错了:

4 4

1

2

4

8



从上面的等式条件,可以进一步变形:

sum[j][2] - sum[j][1] == sum[i-1][2] - sum[i-1][1]

sum[j][3] - sum[j][1] == sum[i-1][3] - sum[i-1][1]

sum[j][4] - sum[j][1] == sum[i-1][4] - sum[i-1][1]

。。。。。。。。。。。。。。。。。。。。

sum[j][k] - sum[j][1] == sum[i-1][k] - sum[i-1][1]

。。。。。。。。。。。。。。。。。。。。

sum[j][K] - sum[j][1] == sum[i-1][K] - sum[i-1][1]

证明很简单,由上面每个式子都能得到 sum[j][k] - sum[i-1][k] = sum[j][1] - sum[i-1][1] 等式右边是个定值.

到这一步, 就再定义C[i][k] = sum[i][k] - sum[i][1], 那么对于某个牛群(从i到 j), 满足黄金平衡的条件就是:

对于任意的k   1 <=k <= K,  C[i-1][k] = C[j][k], 即 sum[i-1][k] - sum[i-1][1] = sum[j][k] - sum[j][1] => sum[j][k] - sum[i-1][k] = sum[j][1] - sum[i-1][1], 再由每个k都满足,即可得到

sum[j][k] - sum[i-1][k]都是相等的, 满足了黄金平衡.

  , 现在黄金平衡条件变成了两个一维数组(C[i] 和 C[j])完全相同.

接下来才开始用hash, 因为要验证数组是否相等, 为了提高效率, 就把数组 整个 都hash,  然后遍历 C[i] 数组(i 从第一头到第N头), 找到匹配成功的, 记下牛群的大小(这需要hash数组也能保存在此位置保存的C数组 是从第几头牛开始计算 得到的, 这样才能算出牛群的大小, 比如 当前是第j , 而匹配的是 第i,那么牛群大小就是 j - i, 因为是从前向后,因此不会有遗漏),与之前进行比较,

如果大就更新

一直到遍历完成, 输出这个过程中最大的牛群数量.

这道题的核心思想不是hash, 而应该是前缀数组和.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值