You are given a colored permutation 𝑝1,𝑝2,…,𝑝𝑛. The 𝑖-th element of the permutation has color 𝑐𝑖.
Let’s define an infinite path as infinite sequence 𝑖,𝑝[𝑖],𝑝[𝑝[𝑖]],𝑝[𝑝[𝑝[𝑖]]]… where all elements have same color (𝑐[𝑖]=𝑐[𝑝[𝑖]]=𝑐[𝑝[𝑝[𝑖]]]=…).
We can also define a multiplication of permutations 𝑎 and 𝑏 as permutation 𝑐=𝑎×𝑏 where 𝑐[𝑖]=𝑏[𝑎[𝑖]]. Moreover, we can define a power 𝑘 of permutation 𝑝 as 𝑝𝑘=𝑝×𝑝×⋯×𝑝𝑘 times.
Find the minimum 𝑘>0 such that 𝑝𝑘 has at least one infinite path (i.e. there is a position 𝑖 in 𝑝𝑘 such that the sequence starting from 𝑖 is an infinite path).
It can be proved that the answer always exists.
Input The first line contains single integer 𝑇 (1≤𝑇≤104) — the number of test cases.
Next 3𝑇 lines contain test cases — one per three lines. The first line contains single integer 𝑛 (1≤𝑛≤2⋅105) — the size of the permutation.
The second line contains 𝑛 integers 𝑝1,𝑝2,…,𝑝𝑛 (1≤𝑝𝑖≤𝑛, 𝑝𝑖≠𝑝𝑗 for 𝑖≠𝑗) — the permutation 𝑝.
The third line contains 𝑛 integers 𝑐1,𝑐2,…,𝑐𝑛 (1≤𝑐𝑖≤𝑛) — the colors of elements of the permutation.
It is guaranteed that the total sum of 𝑛 doesn’t exceed 2⋅105.
Output Print 𝑇 integers — one per test case. For each test case print minimum 𝑘>0 such that 𝑝𝑘 has at least one infinite path.
Example inputCopy 3 4 1 3 4 2 1 2 2 3 5 2 3 4 5 1 1 2 3 4 5 8 7 4 5 6 1 8 3 2 5 3 6 4 7 5 8 4 outputCopy 1 5 2 Note In the first test case, 𝑝1=𝑝=[1,3,4,2] and the sequence starting from 1: 1,𝑝[1]=1,… is an infinite path.
In the second test case, 𝑝5=[1,2,3,4,5] and it obviously contains several infinite paths.
In the third test case, 𝑝2=[3,6,1,8,7,2,5,4] and the sequence starting from 4: 4,𝑝2[4]=8,𝑝2[8]=4,… is an infinite path since 𝑐4=𝑐8=4.
在多校学习置换的时候大佬给的题,现在才开始补嘤嘤。
感觉你会了多校那个置换,这个题就很简单了。
题意: p 2 p^2 p2代表将 p p p数组置换成 p [ p [ i ] ] p[p[i]] p[p[i]], p 3 p^3 p3代表将 p p p数组置换成 p [ p [ p [ i ] ] ] p[p[p[i]]] p[p[p[i]]],以此类推
思路: 首先题目置换实际就是按照 i − > p [ i ] − > p [ p [ i ] ] − > p [ p [ p [ i ] ] ] . . . i->p[i]->p[p[i]]->p[p[p[i]]]... i−>p[i]−>p[p[i]]−>p[p[p[i]]]...建图,这样的话会形成很多个环。
假设某个环的长度为 n n n,环中节点为 a 1 , a 2 , a 3... a1,a2,a3... a1,a2,a3...,置换次数为 k k k 可以发现,当 k k k整除 n n n的时候,实际就是把这个大环分成很多个小环,当 k k k不整除 n n n的时候,只是改变环的顺序,数目还是没变。
因此如果 n = 6 , k = 2 n=6,k=2 n=6,k=2,最后形成两个长度为3的环,为: ( a 1 , a 3 , a 5 ) (a1,a3,a5) (a1,a3,a5), ( a 2 , a 4 , a 6 ) (a2,a4,a6) (a2,a4,a6)。 如果 n = 6 , k = 3 n=6,k=3 n=6,k=3,最后形成三个长度为2的环,为: ( a 1 , a 4 ) (a1,a4) (a1,a4), ( a 2 , a 5 ) (a2,a5) (a2,a5), ( a 3 , a 6 ) (a3,a6) (a3,a6)。
这样你只要找到所有的环,算出其长度和真实节点结构,再枚举要其约数代表要置换多少次,然后O(n) c h e c k check check就好了。
特殊的,如果这个环本身所有对应 c c c数组的值都相同,那么不需要额外置换,答案就是1。
而一个数的因数个数为分解质因数后的质因数个数加一乘积,这个数字不会很大。 所以复杂度为 n l o g ( n ) nlog(n) nlog(n)
#include<cstdio> #include<cstring> #include<algorithm> #include<vector> #include <set> #include <map> #include <queue> using namespace std; typedef long long ll; const int maxn = 2e5 + 7; int p[maxn],c[maxn]; int fa[maxn],cnt[maxn]; int findset(int x) { if(fa[x] == x) return x; return fa[x] = findset(fa[x]); } void Union(int x,int y) { int rx = findset(x),ry = findset(y); if(rx != ry) { fa[rx] = ry; } } bool check(vector<int>vec,int num) { //环上点和间距 int n = vec.size(); for(int i = 0;i < num;i++) { //向后推num位 int flag = 1; for(int j = 0;j < n / num;j++) { // int pos = i + j * num; if(c[vec[pos]] != c[vec[i]]) { flag = 0;break; } } if(flag) return true; } return false; } int main() { int T;scanf("%d",&T); while(T--) { int n;scanf("%d",&n); for(int i = 1;i <= n;i++) { fa[i] = i; cnt[i] = 0; } for(int i = 1;i <= n;i++) { scanf("%d",&p[i]); Union(i,p[i]); } for(int i = 1;i <= n;i++) { scanf("%d",&c[i]); } for(int i = 1;i <= n;i++) { cnt[findset(i)]++; } int ans = 1e9; for(int i = 1;i <= n;i++) { if(cnt[i] == 0) { continue; } int num = cnt[i]; //环的长度 if(num == 1) { ans = 1; break; } int now = i; ans = min(ans,num); vector<int>vec; for(int j = 0;j < num;j++) { //环中节点 vec.push_back(now); now = p[now]; } int flag = 1; for(int j = 0;j < vec.size();j++) { if(c[vec[j]] != c[vec[0]]) { flag = 0;break; } } if(flag) { ans = 1; break; } for(int j = 2;j <= num;j++) { //枚举约数,幂次是多少 if(num % j == 0) { if(check(vec,j)) { ans = min(ans,j);break; } } } } printf("%d\n",ans); } return 0; } //3