题目
题意
给你一个数组然后问你有几种k操作在m此交换下,变成给出的数组
k操作为让后k个数到前面去
做题方法
\(m<=\frac{n}{3}\)所以\(m\)最多影响\(\frac{2n}{3}\)个数字,所以还有\(\frac{n}{3}\)个数字需要\(k\)操作影响
\(cnt[k]+2m>=n\)而\(\sum sum[i]=n\)所以\(k\)最多有3个
然后就回归到经典题目给定一个数组回到另一个数组
\(a\)数组为入点\(b\)数组为出点 然后找会形成环 每个环都需要交换的次数为环上的点-1个
代码
#include <iostream>
#include <string>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <iomanip>
#include <map>
#include <cstdio>
#include <stack>
#include <set>
using namespace std;
typedef long long ll;
typedef pair<int ,int > pii;
#define endl '\n'
const int N = 1e6+10, M = N * 2, inf = 1e8;
int t, n, m, f[N], b[N], a[N];
int find(int x){
return f[x] == x ? x : f[x] = find(f[x]);
}
bool check(){
int sum = 0;
for(int i = 1; i <= n; i++) f[i] = i;
for(int i = 1; i <= n; i++){
if(find(a[i]) != find(b[i])) {
f[a[i]] = b[i];
sum++;
}
}
cout<<sum<<endl;
return sum <= m;
}
int main(){
ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
cin>>t;
while(t--){
cin>>n>>m;
for(int i = 1; i <= n; i++) cin>>b[i];
map<int, int> mp;
for(int i = 1; i <= n; i++) mp[(i-b[i]+n) % n]++;
vector<int> ans;
for(int k = 0; k < n; k++){
if(mp[k] < (n+2)/3) continue;
int flag = 0;
for(int j = 1; j <= n; j++){
a[j] = (j - k + n) % n;
if(a[j] == 0) a[j] = n;
}
if(check()) ans.push_back(k);
}
cout<<ans.size()<<" ";
for(int i = 0; i < ans.size(); i++) cout<<ans[i]<<" ";
cout<<endl;
}
return 0;
}