ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Codeforces Harbour.Space Scholarship Contest 2021-2022/1553E Permutation Shift

2021-07-28 16:31:44  阅读:146  来源: 互联网

标签:cnt const Space int Shift Contest ++ 转置 include


题目链接:https://codeforces.com/contest/1553/problem/E

题目大意:是否能在转置\(k\)轮和交换\(m\)次的条件下将\((1,2,3,...,n)\)变成\((a_{1},a_{2},a_{3},...,a_{n})\),\(0\leq k<n,0\leq m\leq \frac{n}{3}\),转置指元素后移\(k\)位,交换指两个元素交换位置

题目思路:
先将每个数都减\(1\)
转置0轮\((0,1,2,3)\)
转置1轮\((3,0,1,2)\)
转置2轮\((2,3,0,1)\)
转置3轮\((1,2,3,0)\)
不难发现转置k轮实际上就是\(p[i] = i-k(mod \ n)\)
对于每一个转置我们可以求出对a序列来说不动点的个数
a序列为\((1,2,0,3)\)
转置0轮\((0,1,2,3)\),不动点数\(cnt[0] = 1\)
转置1轮\((3,0,1,2)\),不动点数\(cnt[1] = 0\)
转置2轮\((2,3,0,1)\),不动点数\(cnt[2] = 1\)
转置3轮\((1,2,3,0)\),不动点数\(cnt[3] = 2\)
不动点即\(a[i] =p[i] = i-k(mod \ n)\),得 \(k = i-a[i] (mod \ n)\),因\(++cnt[k]\)即可
剩下都是需要移动的点,交换\(m\)次最多可导致\(2m\)个元素交换,因此可以判断如果\(cnt[k]+2m<n\)当前转置就不满足条件,跳过即可
因为\(m\leq \frac{n}{3}\),最多可以交换\(\frac{2n}{3}\)个元素,剩下\(\frac{n}{3}\)是不动点的个数,又因为\(\sum cnt[k] = n\),最多只有3个\(k\)是满足条件的,直接暴力即可
暴力求出环数\(num\),需要移动的点即为\(n-num\)

AC代码:

#include <unordered_map>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <vector>
#include <string>
#include <stack>
#include <deque>
#include <queue>
#include <cmath>
#include <map>
#include <set>
using namespace std;
typedef pair<int, int> PII;
typedef pair<double, int> PDI;
//typedef __int128 int128;
typedef long long ll;
typedef unsigned long long ull;
const int INF = 0x3f3f3f3f;
const int N = 3e5 + 10, M = 4e7 + 10;
const int base = 1e9;
const int P = 131;
const int mod = 1e9 + 7;
const double eps = 1e-9;
const double PI = acos(-1.0);
int a[N], cnt[N], ans[5];
int pos;
bool vis[N];
int main()
{
	int T;
	scanf("%d", &T);
	while (T--)
	{
		pos = 0;
		int n, m;
		scanf("%d%d", &n, &m);
		for (int i = 0; i < n; ++i)
		{
			scanf("%d", &a[i]);
			--a[i];
			++cnt[(i - a[i] + n) % n];
		}
		for (int k = 0; k < n; ++k)
		{
			if (cnt[k] + 2 * m < n)
				continue;
			for (int i = 0; i < n; ++i)
				vis[i] = false;
			int num = 0;
			for (int i = 0; i < n; ++i)
			{
				if (vis[i])
					continue;
				for (int j = i; !vis[j]; j = (a[j] + k) % n)
					vis[j] = true;
				++num;
			}
			if (n - num <= m)
				ans[++pos] = k;
		}
		printf("%d ", pos);
		for (int i = 1; i <= pos; ++i)
			printf("%d ", ans[i]);
		printf("\n");
	}
	return 0;
}

标签:cnt,const,Space,int,Shift,Contest,++,转置,include
来源: https://www.cnblogs.com/xiaopangpangdehome/p/15071135.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有