CF 1553E
题意:
长度为 n 的恒等排列是一个数组 [1,2,3,…,n]。
我们对长度为 n 的恒等排列执行了以下操作:
首先,我们将它循环向右移动 k 个位置,其中 k 对您来说是未知的(您唯一知道的是 0≤k≤n−1)。当一个数组循环向右移动 k 个位置时,结果数组是通过取原始数组的最后 k 个元素(不改变它们的相对顺序),然后将 n−k 个第一个元素追加到它们的右边(不改变它们的顺序)而形成的。也改变前 n-k 个元素的相对顺序)。例如,如果我们将长度为 6 的恒等置换循环移位 2 个位置,我们得到数组 [5,6,1,2,3,4];
其次,我们最多执行以下操作 m 次:选取数组中的任意两个元素并交换它们。
您将获得 n 和 m 的值以及结果数组。您的任务是在循环移位操作中找到 k 的所有可能值。
Input
第一行包含一个整数 t (1≤t≤105)——测试用例的数量。
每个测试用例由两行组成。第一行包含两个整数 n 和 m(3≤n≤3⋅105;0≤m≤n/3)。
第二行包含 n 个整数 p1,p2,…,pn(1≤pi≤n,从 1 到 n 的每个整数在这个序列中只出现一次)——结果数组。
所有测试用例的 n 总和不超过 3⋅105。
Output
对于每个测试用例,按以下方式打印答案:
首先,打印一个整数 r (0≤r≤n)——循环移位操作的 k 可能取值的个数;
其次,打印 r 个整数 k1,k2,…,kr (0≤ki≤n−1) — k 的所有可能值按递增顺序排列。
思路:
首先你需要知道的前提是一个乱序数组需要给它交换成正序的最小花费如何计算。
你可以递归的检查有多少人是形成了一个连通块的,就比如说1占了2的位置,2占了3的位置,3占了1的位置,这就是3个人一个连通块,每个连通块的最小花费就是连通块成员个数-1。
然后这题有一个很重要的条件是m < n/3,说明交换次数是小于n/3的,大胆猜测一下,能够满足这个条件的k会很少,然后暴力跑就行了。
代码:
#include<bits/stdc++.h>
#define ll long long
const int maxn = 3e5 + 5;
const ll mod = 1e9 + 7;
using namespace std;
int p[maxn],num[maxn],nn,ans[maxn];
int nw