题目地址: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 */
poj3274(Gold Balanced Lineup)