首页 > 技术文章 > poj3274(Gold Balanced Lineup)

ZhaoPengkinghold 2014-07-23 15:52 原文

题目地址:Gold Balanced Lineup

 

题目大意:

    一个农场有N个奶牛,每个奶牛都有不同的特征,聪明的农夫给奶牛 feature ID。代表奶牛所具有的特征。将feature ID 写成为K位的二进制的数,其中有1的位置代表奶牛具有此特征,0代表没有此特征。从i->j 使这个区间的奶牛所有特征的个数是相等的。其中最大的区间差就是题图所求的。

 

解题思路:

解题思路:

经典题,不转化问题很难做,先根据官方的方法转化问题,把“求最远的两行间各个特征出现次数相等”转化为“求最远的相同两行”,再用Hash查找。

这是官方解题报告——

Consider the partial sum sequence of each of the k features built by taking the

sum of all the values up to position i. The problem is equivalent to:

Given an array s[n][k], find i,j, with the biggest separation for which s[ i ]

[l]-s[j][l] is constant for all l.

The problem is now to do this efficiently. Notice that s[ i ][l]-s[j][l] being

constant for all l is equivalent to s[ i ][l]-s[j][l]=s[ i ][1]-s[j][1] for all

l, which can be rearranged to become s[ i ][l]-s[ i ][1]=s[j][l]-s[j][1] for all

l. Therefore, we can construct another array a[n][k] where a[ i ][j]=s[ i ][j]-

s[ i ][1] and the goal is to find i and j with the biggest separation for which

a[ i ][l]=a[j][l] for all l.

This can be done by sorting all the a[ i ] entries, which takes O(nklogn) time

(although in practice rarely will all k elements be compared). Another

alternative is to go by hashing, giving an O(nk) solution. Both solutions are

fairly straightforward once the final array is constructed.

 

大概意思就是:

数组sum[i][j]表示从第1到第i头cow属性j的出现次数。

所以题目要求等价为:

求满足

sum[i][0]-sum[j][0]=sum[i][1]-sum[j][1]=.....=sum[i][k-1]-sum[j][k-1] (j<i)

中最大的i-j

 

将上式变换可得到

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

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

......

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

 

令C[i][y]=sum[i][y]-sum[i][0] (0<y<k)

初始条件C[0][0~k-1]=0

 

所以只需求满足C[i][]==C[j][] 中最大的i-j,其中0<=j<i<=n。

C[i][]==C[j][] 即二维数组C[][]第i行与第j行对应列的值相等,

那么原题就转化为求C数组中 相等且相隔最远的两行的距离i-j

 

以样例为例

7 3
7
6
7
2
1
4
2
 

先把7个十进制特征数转换为二进制,并逆序存放到特征数组feature[ ][ ],得到:

7 -> 1 1 1

6 -> 0 1 1

7 -> 1 1 1

2 -> 0 1 0

1 -> 1 0 0

4-> 0 0 1

2 ->0 1 0

(行数为cow编号,自上而下从1开始;列数为特征编号,自左到右从0开始)

 

再求sum数组,逐行累加得,sum数组为

 1 1 1

1 2 2

2 3 3

2 4 3

3 4 3

3 4 4

3 5 4

再利用C[i][y]=sum[i][y]-sum[i][0]求C数组,即所有列都减去第一列

注意C数组有第0行,为全0

 0 0 0 à 第0行

0 0 0

0 1 1

0 1 1

0 2 1

0 1 0

0 1 1

0 2 1

显然第2行与第6行相等,均为011,且距离最远,距离为6-2=4,这就是所求。

需要注意:

但是最大数据有10W个,即10W行,因此不能直接枚举找最大距离,必须用Hash查找相同行,找到相同行再比较最大距离。

我哈希是将K个数求和sum%N,然后放到一个vector里,然后一一比较找出相同序列,哈希的过程中数组可能是负数,所以记得处理负数的可能。

 一个疑问: 如果100000个sum%N的数想同,我代码是不是就超时了呢。

 

代码:

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <sstream>
  4 #include <cstdlib>
  5 #include <cstring>
  6 #include <cstdio>
  7 #include <string>
  8 #include <bitset>
  9 #include <vector>
 10 #include <queue>
 11 #include <stack>
 12 #include <cmath>
 13 #include <list>
 14 //#include <map>
 15 #include <set>
 16 using namespace std;
 17 /***************************************/
 18 #define ll long long
 19 #define int64 __int64
 20 /***************************************/
 21 const int INF = 0x7f7f7f7f;
 22 const double eps = 1e-8;
 23 const double PIE=acos(-1.0);
 24 const int d1x[]= {0,-1,0,1};
 25 const int d1y[]= {-1,0,1,0};
 26 const int d2x[]= {0,-1,0,1};
 27 const int d2y[]= {1,0,-1,0};
 28 const int fx[]= {-1,-1,-1,0,0,1,1,1};
 29 const int fy[]= {-1,0,1,-1,1,-1,0,1};
 30 /*vector <int>map[N];map[a].push_back(b);int len=map[v].size();*/
 31 /***************************************/
 32 void openfile()
 33 {
 34     freopen("data.in","rb",stdin);
 35     freopen("data.out","wb",stdout);
 36 }
 37 /**********************华丽丽的分割线,以上为模板部分*****************/
 38 const int N=1999;
 39 const int MMM=100001;
 40 int n,kk;
 41 int mm;
 42 int maax;
 43 int c[N][35];
 44 typedef struct
 45 {
 46     int a[35];
 47     int sum;
 48     int m;
 49 }node;
 50 node bit[MMM];
 51 vector <node >vc[N];
 52 int cmp()
 53 {
 54     int i,j,k,h;
 55     mm=0;
 56     maax=0;
 57     for(i=0;i<N;i++)
 58        for(j=0;j<vc[i].size();j++)
 59        {
 60            node n1=vc[i][j];
 61            for(k=j+1;k<vc[i].size();k++)
 62            {
 63                node n2=vc[i][k];
 64                if (n1.sum==n2.sum)
 65                {
 66                    for(h=0;h<kk;h++)
 67                        if(n1.a[h]!=n2.a[h])
 68                            break;
 69                     if (h==kk)
 70                     {
 71                         mm=abs(n1.m-n2.m);
 72                         if (maax<mm)
 73                             maax=mm;
 74                     }
 75                }
 76            }
 77        }
 78     return 0;
 79 }
 80 int main()
 81 {
 82     while(scanf("%d%d",&n,&kk)!=EOF)
 83     {
 84         int i,j;
 85         memset(bit,0,sizeof(bit));
 86         memset(c,0,sizeof(c));
 87         int x,y;
 88         for(i=1;i<=n;i++)
 89         {
 90             scanf("%d",&x);
 91             for(j=0;j<kk;j++)
 92             {
 93                 y=x&1;
 94                 bit[i].a[j]=bit[i-1].a[j]+y;
 95                 x>>=1;
 96             }
 97         }
 98      //   int sum=0;
 99         for(i=0;i<=n;i++)
100         {
101             bit[i].sum=0;
102             x=bit[i].a[0];
103             for(j=0;j<kk;j++)
104             {
105                 bit[i].a[j]-=x;
106                 bit[i].sum+=bit[i].a[j];
107             }
108             bit[i].m=i;
109             vc[(bit[i].sum+MMM)%N].push_back(bit[i]);
110         }
111         cmp();
112         printf("%d\n",maax);
113         for(i=0;i<N;i++)
114             vc[i].clear();
115     }
116     return 0;
117 }
118 /*
119 SAMPLE      binary       add       sub
120 7 3         0 0 0
121 7    ->     1 1 1       1 1 1      0 0 0
122 6    ->     1 1 0       2 2 1      1 1 0<---
123 7    ->     1 1 1  ---> 3 3 2  --> 1 1 0   |
124 2    ->     0 1 0       3 4 2      1 2 0   |4
125 1    ->     0 0 1       3 4 3      0 1 0   |
126 4    ->     1 0 0       4 4 3      1 1 0<---
127 2    ->     0 1 0       4 5 3      1 2 0
128 7 3
129 7
130 6
131 7
132 2
133 1
134 4
135 2
136 4
137 
138 7 3
139 7 7 7 7 7 7 7
140 7
141 
142 4 4
143 1
144 2
145 4
146 8
147 4
148 
149 4 4
150 8
151 1
152 2
153 4
154 4
155 
156 5 4
157 3
158 1
159 2
160 4
161 8
162 4
163 
164 1 5
165 3
166 0
167 
168 1 2
169 3
170 1
171 
172 1 3
173 7
174 1
175 */
View Code

 

 代码2:拉链法,时间复杂度低。

P%=MMM。放在if(p<0)后面就是RE 因为P如果是一个小于-100002的数,先+MMM的话得到的还是负数,再取余还是负数就RE。  如果先取余就是得到一个较小的负数。再加MMM就得 到的是正数。不会RE。

  1 #include <algorithm>
  2 #include <iostream>
  3 #include <sstream>
  4 #include <cstdlib>
  5 #include <cstring>
  6 #include <cstdio>
  7 #include <string>
  8 #include <bitset>
  9 #include <vector>
 10 #include <queue>
 11 #include <stack>
 12 #include <cmath>
 13 #include <list>
 14 //#include <map>
 15 #include <set>
 16 using namespace std;
 17 /***************************************/
 18 #define ll long long
 19 #define int64 __int64
 20 /***************************************/
 21 const int INF = 0x7f7f7f7f;
 22 const double eps = 1e-8;
 23 const double PIE=acos(-1.0);
 24 const int d1x[]= {0,-1,0,1};
 25 const int d1y[]= {-1,0,1,0};
 26 const int d2x[]= {0,-1,0,1};
 27 const int d2y[]= {1,0,-1,0};
 28 const int fx[]= {-1,-1,-1,0,0,1,1,1};
 29 const int fy[]= {-1,0,1,-1,1,-1,0,1};
 30 /*vector <int>map[N];map[a].push_back(b);int len=map[v].size();*/
 31 /***************************************/
 32 void openfile()
 33 {
 34     freopen("data.in","rb",stdin);
 35     freopen("data.out","wb",stdout);
 36 }
 37 /**********************华丽丽的分割线,以上为模板部分*****************/
 38 
 39 const int MMM=100001;
 40 int n,kk;
 41 int sum;
 42 int bit[MMM][35];
 43 int c[MMM],next[MMM];
 44 int maax;
 45 int hashcode(int v[])//拉链法
 46 {
 47     int p=0;
 48     int i;
 49     for(i=0; i<kk; i++)
 50         p=(p<<6)+(v[i]>>6)^(v[i]<<6);
 51     p%=MMM;
 52     if (p<0)
 53         p+=MMM;
 54     return p;
 55 }
 56 int cmp(int x,int y)
 57 {
 58     int i,j;
 59     for(i=0; i<kk; i++)
 60     {
 61         if (bit[x][i]!=bit[y][i])
 62             return 0;
 63     }
 64     return 1;
 65 }
 66 int main()
 67 {
 68     scanf("%d%d",&n,&kk);
 69     int i,j;
 70     memset(bit,0,sizeof(bit));
 71     memset(c,-1,sizeof(c));
 72     int x,y;
 73     for(i=1; i<=n; i++)
 74     {
 75         scanf("%d",&x);
 76         for(j=0; j<kk; j++)
 77         {
 78             y=x&1;
 79             bit[i][j]=bit[i-1][j]+y;
 80             x>>=1;
 81         }
 82     }
 83     maax=0;
 84     for(i=0; i<=n; i++)
 85     {
 86         x=bit[i][0];
 87         for(j=0; j<kk; j++)
 88         {
 89             bit[i][j]-=x;
 90         }
 91         int p;
 92         int ce=0;
 93         int h=hashcode(bit[i]);
 94         for(p=c[h]; p!=-1; p=next[p])
 95         {
 96             if (cmp(i,p))
 97             {
 98                 ce=1;
 99                 int mm=i-p;
100                 if (maax<mm)
101                     maax=mm;
102             }
103         }
104         if (!ce)
105         {
106             next[i]=c[h];
107             c[h]=i;
108         }
109     }
110     printf("%d\n",maax);
111     return 0;
112 }
View Code

推荐阅读