CodeForces-Twist the Permutation

题目

看了眼题解,发现大家都写的很高级复杂,于是写了篇我的思路的。

题目

你有一个 \(1\sim n\) 的排列 \(a\),最开始时 \(a_i=i\),你可以对这个排列 \(a\) 执行 \(n\) 次操作,每次指定一个正整数 \(x\) ,第 \(i\) 次时将 \(a_1\sim a_i\) 中的每个数 \(a_j\) 变成 \(a_{j+x\bmod i}\)

先凑点字数。

思路

首先手摸下样例。

6
3 2 5 6 1 4
输出
0 1 1 2 0 4 

像这种题,记住一个原则,正难则易反,于是,我们不妨从最后一个入手。相信大家看了这个图片,就能明白了,没有图片了,管理员说不规范,各个时期变换的数组也没了

6
3 2 5 6 1 4

我们注意到题目说明了规则变换只是针对 \(1\sim i\),那也就是说 \(i+1\) 之后不受影响。

当下标来到了 \(6\) 的时候我们发现此时 \(6\) 跑到了 \(4\) 的位置,原先在$ i$ 小于 \(6\) 之前怎么变换都不会影响到 \(6\),说明了在 \(i\) 等于 \(6\) 时的变换使得 \(6\)\(4\) 去了,说明了此时变换规则是右移两位。

然后我们再还原变换之前的所以数的下标,就是要减去此次的 \(2\),注意取模保证正数,再来看 \(i\) 等于 \(5\) 的时候,我们发现此时 \(5\) 在原位,说明了没有变换,所以这个时候答案是 \(0\),再来到 \(i\) 等于 \(6\),发现它在第二位,很明显它移动了,那移动了多少位呢,其实这个公式是这样的。

i-(i-ma[i))=ma[i]

其中

i-ma[i]

表示了此时相差距离,然后又因为是在 \(1\sim i\) 窗口之内循环于是 \(i\) 减相差距离等于移动距离了,于是发现右移动 \(2\) 位,然后我们再还原下数组得到。

3 2 1 4 5 6

然后来到 \(i\) 等于 \(6\) 发现也是一样不在原位,也是右移动一位。这下明白了吗,快自己模拟下吧!

代码

#include <bits/stdc++.h>
#define int long long
#define endl '\n'
using namespace std;
const int range = 2e5 + 10;
int n;
int ans[range], a[range];
void solve() {
	cin >> n;
	map<int, int>ma;
	for (int i = 1; i <= n; i++)
		cin >> a[i], ma[a[i]] = i;
	for (int i = n; i >= 1; i--) {
		if (i == 1) {
			ans[i] = 0;
			break;
		}
		if (i == ma[i])ans[i] = 0;
		else ans[i] = ma[i];
		for (int j = 1; j <= i - 1; j++)
			ma[j] = (ma[j] - ans[i] + i) % i;
	}
	for (int i = 1; i <= n; i++)	cout << ans[i] << " ";
	cout << endl;
}
signed main() {
	ios::sync_with_stdio();
	cin.tie(0);cout.tie(0);	
	int t;cin >> t;
	while (t--)	solve();	
	return 0;
}

最后

希望大家看了有收获。

posted @ 2025-04-16 19:46  LteShuai  阅读(13)  评论(0)    收藏  举报