首先根据题意我们可以列出以下式子:
当k=1的时候,只需要让数组b的下标与与他的值相等即可。否则不符合条件。
当k>=2s的时候, 可以发现通过L1和L2可以确定数组a中L1位置的值;也就是数L数组中相邻两个数可以修改a数组使其变成符合条件的情况。
怎么得到数组L?首先a_i是要变成b_i的,也就是数L1=i,L_2=b_i;,我可以直接知道L2,因为就b_i本身,那么如何得到L1?我只需要从i向b_i建一条有向边,那么就可以快速知道L1。
由于L_3的位置上是L_1,所以说,如果上面图中的环比k大或者小都会导致在赋值操作中导致出错,而环的大小等于k的时候,完全可以进行依次循环赋值。
所以说,只需要判断建的图中的环的大小就能得到答案。
#include <bits/stdc++.h>
#define int long long
using namespace std;
const int N=100010;
int n,k,a[N];
int vis[N];
void solve(){
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
vis[i]=0;
}
if(k==1){
for(int i=1;i<=n;i++){
if(a[i]!=i){
cout<<"NO"<<'\n';
return;
}
}
printf("YES\n");
return;
}
for(int i=1;i<=n;i++){
if(vis[i]) continue;//与i有关的环已经走过了
int x=i;
set<int> s;
while(!vis[x]){//处理和x有关的环
s.insert(x);
vis[x]=1;x=a[x];
}
//每个数都可能会形成一个环
if(s.count(x)){//如果x在一个没有遍历过的环中,就可以在弄一次
int sz=1;
for(int j=a[x];j!=x;j=a[j],++sz);
//求环的大小
if(sz!=k){
printf("NO\n");
return;
}
}
}
printf("YES\n");
}
signed main(){
int t;
cin>>t;
while(t--){
solve();
}
return 0;
}