这题读了半天才读懂是什么意思=。=!又做了半天才AC=。=!
题意:
有N个奶牛(1<=N<=100,000),每个奶牛有K个特征(1<=K<=30),希望求得第i个奶牛到第j个奶牛满足每一个特征在这个范围内(即j-i+1)都出现了相同的次数。用数据说话:
N=7,K=3
row1:7 | 111
row2:6 | 110
row3:7 | 111
row4:2 | 010
row5:1 | 001
row6:4 | 100
row7:2 | 010
可以发现,row3到row6这个范围内,每个特征都出现了2次,且这一范围(即size=6-3+1=4)是所有满足条件的范围中最大的范围。
思路:(感谢前辈)
首先整理整理各种关系,建立模型!
设sum[i][j]表示前i个奶牛的第j个特征总和,那么根据题意需要满足的条件是:假设1<=a<...<b<=N
sum[b][1]-sum[a][1]=sum[b][2]-sum[a][2]=... ...=sum[b][j]-sum[a][j]=... ...=sum[b][K]-sum[a][K]
上式表示:在{a,b}范围内每个特征出现的次数相等。继续转换上式,得到:
sum[b][2]-sum[b][1]=sum[a][2]-sum[a][1]
sum[b][j]-sum[b][1]=sum[a][j]-sum[a][1]
... ...
sum[b][K]-sum[b][1]=sum[a][K]-sum[a][1]
上式表示:对sum矩阵的第a行和第b行来说,行a的每一列(不是第一列)减去第一列的值等于行b执行相同的计算得到的值。此时我们提取一个模式出来:
设c[i][j]=sum[i][j]-sum[i][1],则根据题意我们需要c矩阵满足的要求是:找到c的两行对应相等且这两行距离最远的两行,它们的距离就是所求的size!
好了,有了这个idea就可以编码实现了。
code:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
const int N = 100010;
const int K = 32;
const int H = 100007;
int n, k, ans;
int feature[N][K];
int sum[N][K];
int c[N][K];
struct Node
{
int pos;
int next;
};
Node node[N];
int cur;
int hashTable[H];
bool compare(int x1, int x2)
{
//判断c矩阵两行是否相等
for (int i = 0; i < k; ++i)
{
if (c[x1][i] != c[x2][i])
return false;
}
return true;
}
bool allsame(int x)
{
for (int i = 0; i < k - 1; ++i)
{
if (sum[x][i] != sum[x][i + 1])
return false;
}
return true;
}
void init()
{
for (int i = 0; i < H; ++i)
hashTable[i] = -1;
ans = 0;
cur = 0;
}
unsigned int getHash(int x)
{
unsigned int hash = 0;
for (int i = 0; i < k; ++i)
{
hash += c[x][i] * (i + 1);
}
return (hash & 0x7fffffff) % H;
}
void searchHash(int x)
{
unsigned int h = getHash(x);
int next = hashTable[h];
while (next != -1)
{
if (compare(node[next].pos, x))
{
if (x - node[next].pos > ans)
ans = x - node[next].pos;
return;
}
next = node[next].next;
}
node[cur].pos = x;
node[cur].next = hashTable[h];
hashTable[h] = cur;
++cur;
}
int main()
{
int val;
init();
cin >> n >> k;
//处理输入数据
for (int i = 0; i < n; ++i)
{
cin >> val;
//构建feature矩阵
for (int j = 0; j < k; ++j)
{
feature[i][j] = (val & 1);
val >>= 1;
}
}
//构建sum矩阵
for (int i = 0; i < k; i++)
sum[0][i] = feature[0][i];
for (int i = 1; i < n; ++i)
{
for (int j = 0; j < k; ++j)
{
sum[i][j] = sum[i - 1][j] + feature[i][j];
}
}
//初始化ans,从后往前,即如果有一组sum的列全相等,则ans=该row值
for (int i = n - 1; i >= 0; --i)
{
if (allsame(i))
{
ans = i + 1;
break;
}
}
//构建c矩阵
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < k; ++j)
{
c[i][j] = sum[i][j] - sum[i][k - 1];
}
}
for (int i = 0; i < n; ++i)
searchHash(i);
cout << ans << endl;
//system("pause");
return 0;
}
特征匹配算法
1946

被折叠的 条评论
为什么被折叠?



