1327D Infinite Path(图论+思维)
题意:有 T T T 个询问,每个询问有长度为 n n n 的被染色排列 p 1 ∼ p n p_1\sim p_n p1∼pn,第 i i i 位被染色为 c i c_i ci,排列中每位数字都处于循环 i , p [ i ] , p [ p [ i ] ] . . . i, p[i], p[p[i]]... i,p[i],p[p[i]]... 中,若该循环中每个数字的颜色都相同则认为该循环为有效的。现在有一个操作,让该排列每个数字 p [ i ] p[i] p[i] 变成 p [ p [ i ] ] p[p[i]] p[p[i]]。现在问至少需要多少次操作才会出现有效的循环。
范围: 1 ≤ T ≤ 1 e 4 , 1 ≤ n ≤ 2 e 5 , 1 ≤ p i ≤ n , 1 ≤ c i ≤ n 1 \le T \le 1e4~,~1 \le n \le 2e5~,~1 \le p_i \le n~,~1 \le c_i \le n 1≤T≤1e4 , 1≤n≤2e5 , 1≤pi≤n , 1≤ci≤n
分析:根据题意序列中每个数字都处于环中,只有当环中的所有点颜色相同才为有效,进行一次操作后构造出新的图中可能会形成更小的环,我们需要求多少次操作后才会出现所有点颜色相同的环。可以发现当进行操作的次数 k k k 为环长 l l l 的因数时才会形成更小的环,因此我们可以先预处理出所有的环,对每个环枚举其所有因数,验证是否出现有效的环。时间复杂度大约为 O ( n n ) O(n\sqrt{n}) O(nn)。
Code:
#include <bits/stdc++.h>
#define int long long
#define double long double
using namespace std;
const int MAXN = 2e5 + 10;
const int INF = 0x3f3f3f3f;
const int MOD = 1e9 + 7;
const double eps = 1e-9;
const double PI = acos(-1.0);
int n;
inline int read()
{
int s = 0, w = 1;
char ch = getchar();
while (ch < '0' || ch > '9')
{
if (ch == '-')
w = -1;
ch = getchar();
}
while (ch >= '0' && ch <= '9')
s = s * 10 + ch - '0', ch = getchar();
return s * w;
}
int p[MAXN], c[MAXN], vis[MAXN];
signed main()
{
int T = read();
while (T--)
{
n = read();
for (int i = 0; i <= n; i++)
vis[i] = 0;
for (int i = 1; i <= n; i++)
{
p[i] = read();
}
for (int i = 1; i <= n; i++)
{
c[i] = read();
}
int ans = INF;
for (int i = 1; i <= n; i++)
{
// 已经位于环中的点不必再处理
if (vis[i])
continue;
// cycle保存该环中的所有点
vector<int> cycle;
int now = i;
while (cycle.empty() || now != i)
{
cycle.push_back(now);
vis[now] = 1;
now = p[now];
}
int sz = cycle.size();
// 枚举所有长度
for (int step = 1; step <= sz; step++)
{
// 必须要是因数才有意义
if (sz % step)
continue;
// 此时以环中第j个元素作为起点进行检查
for (int j = 0; j < step; j++)
{
int color = c[cycle[j]];
int flag = 0;
for (int k = j; k < sz; k += step)
{
// 如果新环中点颜色不同则不满足条件
if (c[cycle[k]] != color)
{
flag = 1;
break;
}
}
// 新环中所有点颜色相同则更新答案
if (!flag)
{
ans = min(ans, step);
break;
}
}
}
}
cout << ans << endl;
}
return 0;
}
【END】感谢观看