题目大意:
就是将一个长度为 n n n的 [ 1 , 2 , 3 , 4 , 5 , 6 , . . . , n ] [1,2,3,4,5,6,...,n] [1,2,3,4,5,6,...,n]的数组先向右旋转 K K K步,然后在 s w a p swap swap最多 m m m次,现在给你最后的结果,问你 K K K可能是什么?
解题思路:
又是一个小技巧
1.首先我们知道交换后再旋转,和旋转后再交换是一样的
2.对于两个全排列
a
,
b
a,b
a,b的
a
−
>
b
a->b
a−>b的最小交换次数等于
(
a
i
,
b
i
)
(a_i,b_i)
(ai,bi)连接无向边然后
n
−
c
n-c
n−c然后
c
c
c是图的联通块个数
3.但是每次检测是
O
(
n
)
O(n)
O(n)的我们不能对每个
K
K
K都检测一遍
5.我们发现对于交换后,最多只会有
2
∗
m
2*m
2∗m个数不在原来的位置,那么就有
n
−
2
∗
m
n-2*m
n−2∗m会在原来的位置
#include <bits/stdc++.h>
#define mid ((l + r) >> 1)
#define Lson rt << 1, l , mid
#define Rson rt << 1|1, mid + 1, r
#define ms(a,al) memset(a,al,sizeof(a))
#define log2(a) log(a)/log(2)
#define lowbit(x) ((-x) & x)
#define IOS std::ios::sync_with_stdio(0); cin.tie(0); cout.tie(0)
#define INF 0x3f3f3f3f
#define LLF 0x3f3f3f3f3f3f3f3f
#define f first
#define s second
#define endl '\n'
using namespace std;
const int N = 2e6 + 10, mod = 1e9 + 9;
const int maxn = 500010;
const long double eps = 1e-5;
const int EPS = 500 * 500;
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int,int> PII;
typedef pair<ll,ll> PLL;
typedef pair<double,double> PDD;
template<typename T> void read(T &x)
{
x = 0;char ch = getchar();ll f = 1;
while(!isdigit(ch)){if(ch == '-')f*=-1;ch=getchar();}
while(isdigit(ch)){x = x*10+ch-48;ch=getchar();}x*=f;
}
template<typename T, typename... Args> void read(T &first, Args& ... args)
{
read(first);
read(args...);
}
int n, m;
int arr[maxn], cnt[maxn];
vector<int> ans, Graph[maxn];
bool vis[maxn];
void dfs(int u) {
vis[u] = 1;
for(auto it : Graph[u]) {
if(vis[it]) continue;
dfs(it);
}
}
inline bool check(int loop) {//先转再去check要多少次交换
for(int i = 0; i < n; ++ i) Graph[i].clear(), vis[i] = 0;
for(int i = 0; i < n; ++ i)
Graph[arr[i]-1].push_back((i-loop+n)%n), Graph[(i-loop+n)%n].push_back(arr[i]-1);
int tg = 0;
for(int i = 0; i < n; ++ i)
if(!vis[i])
dfs(i),tg ++;
return n - tg <= m;
}
inline void slove() {
ans.clear();
cin >> n >> m;
for(int i = 0; i < n; ++ i) cnt[i] = 0;
for(int i = 0; i < n; ++ i) cin >> arr[i];
for(int i = 0; i < n; ++ i) {
int offset = i - (arr[i] - 1);
if(offset < 0) offset += n;
cnt[offset] ++;
}
for(int i = 0; i < n; ++ i)
if(cnt[i] + 2 * m >= n && check(i))
ans.push_back(i);
cout << ans.size() << " ";
for(auto it : ans) cout << it << " ";
cout << "\n";
}
int main() {
IOS;
int T;
cin >> T;
while(T -- ) {
slove();
}
return 0;
}