CF-#Round 84-div2-D题
D. Infinite Path
这道题比E题难些=-=(虽然我没写,我是看ac人数看的emmm)
今天蓝桥杯的校内模拟赛出来了。
伤心了。。。抑郁了一会会。。13。。。啊啊啊这是什么鬼名次。校内都13。。。
还是题目刷的不够不精。。这样下去能不能进决赛都是问题。。
题目大意:给定了一个序列。以及他们所含有的颜色。
给出了p^k = p * p * p *…*p定义。乘方定义
问使得最小的k使得某无限的序列中颜色一样。
这个题目转换成图论就行。dfs
把图画出来。
就是下标为1的指向数组下标为1的内容的数字。
依次这么转换,这个转换应该还挺简单的。。
因为我都想得到哈哈哈
我们转换为图之后会形成互不干扰的多个环。
p^k转换为在图中走k步。
我们把每个环的结点个数cnt记录下来。
考虑求每个环结点个数cnt的因数。
为啥?
因为我们可以模拟一下。
当i不是cnt的因数时。模拟下来仍然是一个环。就是顺序变了
当i是cnt的因数时。我们可以把当前环分成多个小环了。此时小环的结点个数时cnt / i;我们就判断小环的结点的颜色是否相同。这个地方好判断
所以我们就用dfs()分成多个环。
用judge()判断小环是否满足颜色相同的要求。
维护一下ans最小值就行。
在judge()函数中有一个下标处理:
走x步之后到达结点的颜色。因为我们需要mod cnt嘛。然后如果恰好为cnt的倍数之后,mod求余完是0,但是我们颜色记录是从1开始的。
所以小tips:i = (i + x - 1) % cnt + 1;
这样可以保证可以到达cnt。没有0的情况
嘿嘿。这里卡了一会。
代码部分:
#include <bits/stdc++.h>
#define mst(a, n) memset(a, n, sizeof(a))
using namespace std;
const int N = 2e5 + 10;
const int INF = 1e9 + 10;
int p[N];
int c[N];
int tmp[N];
int vis[N];
int ans;
int cnt;
int n;
int judge(int x, int y)
{
for (int i = 1; i <= x; i++)
{
int t = i;
int flag = 0;
for (int j = 1; j <= y; j++)
{
if (c[tmp[t]] != c[tmp[i]])
{
flag = 1;
break;
}
t = (t + x - 1) % cnt + 1;
}
if (!flag)
{
return 1;
}
}
return 0;
}
void dfs(int x)
{
cnt = 0;
tmp[++cnt] = x;
vis[x] = 1;
for (int i = p[x]; i != x; i = p[i])
{
tmp[++cnt] = i;
vis[i] = 1;
}
for (int i = 1; i * i <= cnt; i++)
{
if (!(cnt % i))
{
if (judge(i, cnt / i))
{
ans = min(ans, i);
return ;
}
if (judge(cnt / i, i))
{
ans = min(ans, cnt / i);
}
}
}
}
int main()
{
int t;
cin >> t;
while (t--)
{
cin >> n;
mst(vis, 0);
for (int i = 1; i <= n; i++)
{
scanf ("%d", &p[i]);
}
for (int i = 1; i <= n; i++)
{
scanf ("%d", &c[i]);
}
ans = INF;
for (int i = 1; i <= n; i++)
{
if (!vis[i])
{
dfs(i);
}
}
cout << ans << endl;
}
return 0;
}