• POJ3274-牛的属性-HASH-ACM


    原题POJ3274

    参考:进击的阿俊


    已知有n头牛,用一个K位二进制数Ak,Ak-1,...,A1表示一头牛具有的特征,Ai=1表示具有特征i。现给定按顺序排列的N头牛的k位特征值,称某个连续范围内“特征平衡”,假如在这个范围内,拥有各个特征的牛的数量都相等。求最大“特征平衡”连续范围。

    分析:

    用sum[i][j]( 1<=i<=n, 1<=k<=j)表示1到第i头牛中具有特征j的牛的数量。问题转化为求解满足sum[i][l] - sum[j][l] = sum[i][1] - sum[j][1](l = 1,2,..,k)的最大i - j的值。很容易想到最简单的方法,通过令d = n to 1,判断是否存在i,使得sum[i + d][j] - sum[i][j] = sum[i + d][1] - sum[i][j],时间复杂度为O(n*n*k)。由于n的最大值能达到100000,必须选择一个更加优化的方法。

    1)容易验证,sum[i][l] - sum[j][l] = sum[i][1] - sum[j][1] ( l = 1,2,..,k ) 等价于sum[i][l] - sum[i][1] = sum[j][l] - sum[j][1] ( l = 1,2,...k )。因此令d[i][j] =  sum[i][j] - sum[i][1] ,问题就转化为求解使得d[i][j] = d[i + size][j]的最大size。

    2)为进一步简化算法,对于任意 1<= i <=n, 令sig[i] = (d[i][1] + d[i][2] + ... +d[i][k] ) % m (m为一个较大的质数)。这样,若对于i和j, sig[i] != sig[j],那么必定不会满足d[i][] = d[j][],就无需再对它进行验证;若满足sig[i] = sig[j],才需要进一步确定是否有d[i][] = d[j][]。

    3)用h[k] (1 <= k <= m,m为以上取模运算的素数)记录满足sig[i] = k的i值。通过令 i = 1 to n,以此更新h[sig[i]]和largest,即可得到结果。


    样例输入

    7 3
    7
    6
    7
    2
    1
    4
    2

    样例输出


    4


    图示


    //
    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <vector>
    #include <cmath>
    
    using namespace std;
    
    const int maxn = 100010;
    const int maxk = 31;
    int n, k, tmp;
    bool cow[maxn][maxk];
    int sum[maxn][maxk];
    int d[maxn][maxk];	//d 和 sig辅助计算哈希值
    int s, size;
    const int prime = 49117;
    int sig[maxn];
    int largest;
    
    vector <int> h[prime];		//哈希表
    
    void search(int i, int t)//0 1  2 2  2 3  3 4  
    {
        int size = h[i].size();
        for (int j = 0; j < size; j++) {
            bool flag = 1;
            for (int l = 0; l < k; l++) {
    //printf("d[h[%d][%d]:%d][%d]:%d ==? d[%d][%d]:%d
    ",i,j,h[i][j],l,d[h[i][j]][l],t,l,d[t][l]);
                if ( d[ h[i][j] ][l] != d[t][l] ) {
                    flag = 0;
                    break;
                }
            }
            if (flag) {
                if (t - h[i][j] > largest)
                    largest = t - h[i][j];
                return;
            }
        }
        h[i].push_back(t);
    //printf("i:%d push back t:%d
    ",i,t);
    }
    
    
    int findLargest()
    {
        largest = 0;
        for (int i = 1; i <= n; i++) {
            search(sig[i], i);
    		printf("%d
    ",largest);
        }
        return largest;
    }
    
    void init()
    {
        memset(sum, 0, sizeof(sum));
        memset(sig, 0, sizeof(sig));
        for (int i = 0; i < prime; i++) h[i].clear();
        h[0].push_back(0);
        for (i = 1; i <= n; i++) {
            for (int j = 0; j < k; j++) {
                sum[i][j] = sum[i - 1][j] + cow[i][j];
                d[i][j] = sum[i][j] - sum[i][0];
    			sig[i] += d[i][j];
    //printf("%d ",d[i][j]);
    //printf("%d ",d[i][j]);
            }
    //printf("%d
    ",sig[i]);
    		/*
            for (j = 0; j < k; j++) {
                sig[i] += d[i][j];
            }
    		*/
            sig[i] = abs(sig[i]) % prime;
        }
    }
    
    int main()
    {
        //while (1) {
        scanf("%d%d", &n, &k);
        for (int i = 1; i <= n; i++ ) {
            scanf("%d", &tmp);
            for (int j = 0; j < k; j++) {
                cow[i][j] = tmp % 2;
                tmp /= 2;
            }
        }
        init();
        findLargest();
        printf("%d
    ", largest);
        //}
        return 0;
    }
    
  • 相关阅读:
    C# 计算结果四舍五入
    同时执行多条SQL语句
    将一个datatable的值赋给另一个dt的三种方法转
    Oracle中增加、删除、修改字段
    Oracle 某列转为行
    DataList中链接跳转页面传参数
    修改数据库中多个表中的同一个字段的长度(可参照修改成同一字段的列名、注释等)
    克隆表结构
    博客专题
    Rational Rose2003 安装教程
  • 原文地址:https://www.cnblogs.com/lvyahui/p/4009939.html
Copyright © 2020-2023  润新知