1327D Infinite Path(图论+思维)

1327D Infinite Path(图论+思维)

题面

题意:有 T T T 个询问,每个询问有长度为 n n n 的被染色排列 p 1 ∼ p n p_1\sim p_n p1pn,第 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 1T1e4 , 1n2e5 , 1pin , 1cin

分析:根据题意序列中每个数字都处于环中,只有当环中的所有点颜色相同才为有效,进行一次操作后构造出新的图中可能会形成更小的环,我们需要求多少次操作后才会出现所有点颜色相同的环。可以发现当进行操作的次数 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】感谢观看

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值