D. Cyclic Operations Codeforces Round 897 (Div. 2)

Problem - D - Codeforces

题目大意:有一个长度为n的数组a,每次操作可以选取一个长度为k的所有数互不相同的数组b,令abi=bi%k+1,问能否将一个全为零的数组通过任意次操作得到a

1<=k<=n<=1e5

思路:通过上述操作,我们发现k中每两个数可以把一个位置修改成目标值,例如对于题目中给的样例1,我们要将a1修改成2,那么k就应该等于1,2,?,要将a2修改成3,k就等于2,3,?,但问号里的数不能与前面的重复也不能超过n,所以可能会覆盖掉之前修改过的数,如果我们从i向ai建边,那么存在覆盖就代表着图中存在环。样例1的环如下:

对于单一约束的点,也就是环以外的点,直接按顺序操作即可,对于环内的点,当环的大小大于k时,也就是如下图:

我们先按顺序操作1,2,3,3,5,4,使位置1,2,3,5上的数都修改完毕,要让位置4上的数也修改好,只能是4,2,3,这是会把3修改成4,而我们要的是5,要把3改回去,就要操作3,5,4,第4个位置又不行了,所以这样的环永远会出现错误覆盖的情况。

但环的大小小于k时,例如1,2互向指向自己,那k=3时的操作就只能是1,2,1,后面填别的数都会错误的覆盖掉其他位置,而这样又与b种数字不能重复矛盾,所以这样的话也没法修改好。

综上,只有所有环的大小等于k时才有合法操作方案,我们首先从入度为0的点开始遍历,先用类似拓扑排序的方法去掉所有环外的点,然后再遍历所有环,检查大小是否为k。

除此之外,还要特判k=1的情况,因为这时只能将第i个位置上的数修改成i,检查a数组即可

cpp 复制代码
#include<bits/stdc++.h>
//#include<__msvc_all_public_headers.hpp>
using namespace std;
typedef long long ll;
const int N = 1e5 + 5;
int n;
bool vis[N];
int to[N];
int in[N];
void init()
{
	for (int i = 1; i <= n; i++)
	{
		in[i] = 0;
		vis[i] = 0;
	}
}
int cnt = 0;
void dfs(int u)
{//遍历环
	vis[u] = 1;
	cnt++;//统计环的大小
	int v = to[u];
	if (!vis[v])
	{
		dfs(v);
	}
}
void solve()
{
	int k;
	cin >> n >> k;
	init();
	if (k == 1)
	{//特判k=1的情况
		bool flag = 1;
		for (int i = 1; i <= n; i++)
		{
			int x;
			cin >> x;
			if (x != i)
				flag = 0;
		}
		cout << (flag ? "Yes" : "No") << endl;
		return;
	}
	for (int i = 1; i <= n; i++)
	{
		int v;
		cin >> v;
		in[v]++;
		to[i] = v;//从i向a[i]建边
	}
	queue<int>q;
	for (int i = 1; i <= n; i++)
	{//放入入度为0的点
		if (!in[i])
		{
			q.push(i);
		}
	}
	while (!q.empty())
	{//用类似拓扑排序的方式标记所有环外的点
		int u = q.front();
		q.pop();
		vis[u] = 1;
		int v = to[u];
		in[v]--;
		if (!in[v])
		{
			q.push(v);
		}
	}
	for (int i = 1; i <= n; i++)
	{//遍历所有环
		if (!vis[i])
		{
			cnt = 0;
			dfs(i);
			if (cnt != k)
			{//检查环的大小是否等于k
				cout << "No" << endl;
				return;
			}
		}
	}
	cout << "Yes" << endl;
}
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while (t--)
	{
		solve();
	}
	return 0;
}
相关推荐
CQU_JIAKE6 分钟前
10.1[A]2267,磐久UMX【上下文128K,KVCache部分]
算法
朝朝辞暮i11 分钟前
C++ 第 14 课:引用 &
开发语言·c++·算法
白山编程大哥22 分钟前
适合初学者练习的 C/C++ 开源项目推荐
c语言·c++·开源
Joe_Wang530 分钟前
【从0到1学习JVM · 21】既不浪费空间又没有碎片,标记整理算法到底慢在哪
jvm·学习·算法·垃圾回收·标记整理算法
让学习成为一种生活方式36 分钟前
PlantCellChat--单细胞与空间转录组数据预测植物细胞间通讯的R包--The Plant Journal
算法
C++ 老炮儿的技术栈1 小时前
有符号变量与无符号变量的区别
服务器·开发语言·前端·数据结构·c++·算法·c
个 人 练 习 生1 小时前
C++:模板初阶详解
开发语言·c++·经验分享·学习
梦帮科技1 小时前
多任务权重流形融合:SLERP 球形线性插值、DARE 稀疏剪枝与多专家模型融合落地
人工智能·深度学习·算法·机器学习·tensorflow·聚类·剪枝
Tisfy1 小时前
LeetCode 0020.有效的括号:栈匹配
算法·leetcode·字符串·题解·括号匹配
知识分享小能手1 小时前
C++ 学习教程,从入门到精通,C++类继承 — 完整知识点详解(13)
开发语言·c++·学习