CF1043D Mysterious Crime

时间:2023-03-09 22:10:35
CF1043D Mysterious Crime

思路:

参考了http://codeforces.com/blog/entry/62797,把第一个序列重标号成1,2,3,...,n,在剩下的序列中寻找形如x, x + 1, x + 2, ...的连续子段即可。

实现:

 #include <iostream>
#include <vector>
#include <cstring>
using namespace std;
typedef long long ll; const int INF = 0x3f3f3f3f; int a[][], reach[][], n, m; int main()
{
while (scanf("%d %d", &n, &m) != EOF)
{
memset(reach, , sizeof reach);
for (int i = ; i <= m; i++)
{
for (int j = ; j <= n; j++)
scanf("%d", &a[i][j]);
}
vector<int> v(n + );
for (int i = ; i <= n; i++) v[a[][i]] = i;
for (int i = ; i <= m; i++)
{
for (int j = ; j <= n; j++)
a[i][j] = v[a[i][j]];
}
for (int i = ; i <= n; i++) reach[][i] = n;
for (int i = ; i <= m; i++)
{
int j = , start = ;
while (j <= n)
{
while (j + <= n && a[i][j + ] == a[i][j] + ) j++;
while (start <= j) { reach[i][a[i][start]] = a[i][j]; start++; }
start = ++j;
}
}
ll ans = ;
for (int i = ; i <= n; i++)
{
int minn = INF;
for (int j = ; j <= m; j++)
if (reach[j][i])
minn = min(minn, reach[j][i] - i + );
if (minn != INF) ans += minn;
}
printf("%lld\n", ans);
}
return ;
}