题意
给一个n个数的数列a,a[i]<=n
定义一个操作:每次可以交换任意位置的两个值;
定义最优操作:对于任意一个原数列的一组排列,使其通过尽可能少的操作变回原数列;
求构造一组原数列的一组排列,使得在最优操作下操作次数尽可能多;
一开始读错题了,读成只能交换相邻点,一直在考虑逆序对,终于写出来了以后,一直wa,才发现原来是任意点交换,哭
提示
1. 考虑每个点的值没有重复的话,那么很简单,直接构建一个环就好了,操作次数N-1
2. 考虑到有两个相同数值的在一个环里的话,那么就可以分裂成两个环,这样最优解的个数就能减一
3. 因此只需要每次构建一个环,把所有数值的点每次囊括进去一个,直到没有环就好了
代码
#includeusing namespace std;vector G[200005];int a[200005], b[200005];void run() { int n; cin >> n; for (int i = 1; i <= n; i++) { G[i].clear(); } for (int i = 1; i > x; a[i] = x; G[x].emplace_back(i); } set cnt; for (int i = 1; i <= n; i++) { if (G[i].size())cnt.emplace(i); } int sum = 0; while (sum < n) { vector now, u; for (auto k: cnt) { now.emplace_back(G[k].back()); G[k].pop_back(); if (G[k].size() == 0) { u.emplace_back(k); } } sum += now.size(); for (int i = 0; i < now.size() - 1; i++) { b[now[i + 1]] = a[now[i]]; } b[now[0]] = a[now[now.size() - 1]]; for (auto k: u)cnt.erase(k); } for (int i = 1; i <= n; i++)cout << b[i] <> t; while (t--) run(); return 0;}