POJ3274

原题: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\n",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\n",i,t);
}

int findLargest()
{
    largest = 0;
    for (int i = 1; i <= n; i++) {
        search(sig[i], i);
		printf("%d\n",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\n",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\n", largest);
    //}
    return 0;
}
时间: 2024-10-11 12:10:12

POJ3274的相关文章

POJ3274 hash

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

poj3274(Gold Balanced Lineup)

题目地址:Gold Balanced Lineup 题目大意: 一个农场有N个奶牛,每个奶牛都有不同的特征,聪明的农夫给奶牛 feature ID.代表奶牛所具有的特征.将feature ID 写成为K位的二进制的数,其中有1的位置代表奶牛具有此特征,0代表没有此特征.从i->j 使这个区间的奶牛所有特征的个数是相等的.其中最大的区间差就是题图所求的. 解题思路: 解题思路: 经典题,不转化问题很难做,先根据官方的方法转化问题,把“求最远的两行间各个特征出现次数相等”转化为“求最远的相同两行”,

poj3274解题报告

1.题目大意为找出i到j头牛之间各种特性出现次数相同,且输出j-i的最大值: 2.我们可以求出sum[i][j],即从开始到头牛时j特性出现的次数,假设i与j之间1特性出现的次数相同,则ij之间其他各个特性对1的差对应相等, 因此 我们可以利用sum[i][j]-sum[i][1];构造key值用哈希查找. 3.易错点,加入hash是sum[0][j],也要考虑,否则就无法将第一头牛计算在内,其次读数要用scanf: 4.源码 #include<iostream>#include<alg

acm常见算法及例题

转自:http://blog.csdn.net/hengjie2009/article/details/7540135 acm常见算法及例题 初期:一.基本算法:     (1)枚举. (poj1753,poj2965)     (2)贪心(poj1328,poj2109,poj2586)     (3)递归和分治法.     (4)递推.     (5)构造法.(poj3295)     (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)二.图算法

ACM算法总结及刷题参考

参考:http://bbs.byr.cn/#!article/ACM_ICPC/11777 OJ上的一些水题(可用来练手和增加自信)(poj3299,poj2159,poj2739,poj1083,poj2262,poj1503,poj3006,poj2255,poj3094) 初期: 一.基本算法: (1)枚举. (poj1753,poj2965)    (2)贪心(poj1328,poj2109,poj2586)    (3)递归和分治法.     (4)递推.     (5)构造法.(po

POJ题目推荐(转载)

POJ推荐50题1.标记“难”和“稍难”的题目可以看看,思考一下,不做要求,当然有能力的同学可以直接切掉.2.标记为A and B的题目是比较相似的题目,建议大家两个一起做,可以对比总结,且二者算作一个题目.3.列表中大约有70个题目.大家选做其中的50道,且每类题目有最低数量限制.4.这里不少题目在BUPT ACM FTP上面都有代码,请大家合理利用资源.5.50个题目要求每个题目都要写总结,养成良好的习惯.6.这个列表的目的在于让大家对各个方面的算法有个了解,也许要求有些苛刻,教条,请大家谅

POJ题目分类

初期: 一.基本算法:     (1)枚举. (poj1753,poj2965)     (2)贪心(poj1328,poj2109,poj2586)     (3)递归和分治法.     (4)递推.     (5)构造法.(poj3295)     (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)二.图算法:     (1)图的深度优先遍历和广度优先遍历.     (2)最短路径算法(dijkstra,bellman-ford,floyd,he

嗷嗷嗷,kuangbin大大博客上拉的题

正在学(learning),未学(waiting),已学(cut  vovering) 初期:一.基本算法:     (1)枚举. (poj1753,poj2965)     (2)贪心(poj1328,poj2109,poj2586)     (3)递归和分治法.     (4)递推.     (5)构造法.(poj3295)     (6)模拟法.(poj1068,poj2632,poj1573,poj2993,poj2996)二.图算法:     (1)图的深度优先遍历和广度优先遍历.  

转:转一个搞ACM需要的掌握的算法. .

要注意,ACM的竞赛性强,因此自己应该和自己的实际应用联系起来.  适合自己的才是好的,有的人不适合搞算法,喜欢系统架构,因此不要看到别人什么就眼红,  发挥自己的长处,这才是重要的. 第一阶段:练经典常用算法,下面的每个算法给我打上十到二十遍,同时自己精简代码,  因为太常用,所以要练到写时不用想,10-15分钟内打完,甚至关掉显示器都可以把程序打  出来.  1.最短路(Floyd.Dijstra,BellmanFord)  2.最小生成树(先写个prim,kruscal要用并查集,不好写)