• 【CF1553E】Permutation Shift


    题目描述

    An identity permutation of length (n) is an array ([1,2,3,cdots,n]).

    We performed the following operations to an identity permutation of length (n):

    firstly, we cyclically shifted it to the right by (k) positions, where (k) is unknown to you (the only thing you know is that (0le kle n−1)). When an array is cyclically shifted to the right by (k) positions, the resulting array is formed by taking (k) last elements of the original array (without changing their relative order), and then appending (n−k) first elements to the right of them (without changing relative order of the first (n−k) elements as well). For example, if we cyclically shift the identity permutation of length (6) by (2) positions, we get the array ([5,6,1,2,3,4]);
    secondly, we performed the following operation at most m times: pick any two elements of the array and swap them.
    You are given the values of (n) and (m), and the resulting array. Your task is to find all possible values of (k) in the cyclic shift operation.

    题目大意

    将长度为 (n) 的数组 ([1,2,3,cdots,n]) 的前 (k) 位与后 (n-k) 位整体交换位置,并且再交换不超过 (m(mle frac{n}{3})) 个位置,给出最终的数组,问有多少个可能的 (k).

    思路

    位置不影响交换,所以我们枚举 (k) 将后 (k) 位换回来并且判断是否可以在 (m) 次交换内还原成 ([1,2,cdots,n]).

    首先有一个结论,满足条件的 (k) 不超过 (3) 个. 我们令 (cnt_k) 为向后位移 (k) 后的序列有多少个不需要交换的位置,即 (a_i=i)(i) 的个数,每次最多交换两个数,所以如果需要交换的数的个数超过 (2m) 那一定不合法,即 (cnt_k ge n-2mge n-frac{n}{3} imes 2=frac{n}{3}). 而且有 (Sigma cnt_k=n),所以合法的 (k) 一定不超过 (3) 个.

    所以每次暴力 (O(n)) 并查集计算交换关系的环的个数,判断交换次数是否小于 (m).

    #include <cstring>
    #include <vector>
    #include <cstdio>
    using namespace std;
    const int maxn = 3e5 + 10;
    int t,n,m,p[maxn],fa[maxn],cnt[maxn];
    vector<int> ans;
    inline int find(int x) { return fa[x] = (fa[x] ^ x ? find(fa[x]) : x); }
    inline void uni(int x,int y) { x = find(x); y = find(y); fa[x] = y; }
    inline bool check(int k) {
    	for (int i = 1;i <= n;i++) fa[i] = i;
    	int tot(0),a[maxn];
    	for (int i = n-k+1;i <= n;i++) a[++tot] = p[i];
    	for (int i = 1;i <= n-k;i++) a[++tot] = p[i];
    	for (int i = 1;i <= n;i++) if (a[i] ^ i) uni(a[i],i);
    	tot = 0;
    	for (int i = 1;i <= n;i++) if (a[i] ^ i && fa[i] == i) tot++;
    	return n-cnt[k]-tot <= m;
    }
    int main() {
    	for (scanf("%d",&t);t--;puts(""),ans.clear()) {
    		scanf("%d%d",&n,&m);
    		for (int i = 1;i <= n;i++) {
    			scanf("%d",&p[i]);
    			cnt[(p[i]-i+n)%n]++;
    		}
    		if (cnt[0] >= n-m*2 && check(0)) ans.push_back(0);
    		for (int i = n-1;i;i--)
    			if (cnt[i] >= n-m*2 && check(i)) ans.push_back(n-i);
    		printf("%d",(int)ans.size());
    		for (size_t i = 0;i < ans.size();i++) printf(" %d",ans[i]);
    		for (int i = 1;i <= n;i++) cnt[(p[i]-i+n)%n]--;
    	}
    	return 0;
    }
    
  • 相关阅读:
    多态的使用
    抽象类与具体类
    对象应该长什么样子
    方法的重载overload
    遵守合约:覆盖的规则
    Android 自定义Dialog
    less 之Extend 及 Extend all用法
    github常见错误整理!
    js获取元素宽高
    解决 Error: Access denied for user 'root'@'localhost' (using password: YES)
  • 原文地址:https://www.cnblogs.com/lrj124/p/15368987.html
Copyright © 2020-2023  润新知