【2023年中山市东区青少年信息学奥林匹克竞赛小学组】第四题:反转顺序(swap)

描述

Jimmy老师的N头宠物吃饱后(1≤N≤100)站成了一排。对于每一个1≤i≤N,从左往右数第i头宠物的编号为i。他想到了一个新的晨练方案给这些宠物。他让她们重复以下包含两个步骤的过程K(1≤K≤109,109表示10的9次方)次:
当前从左往右数在位置A1…A2的宠物序列反转她们的顺序(1≤A1<A2≤N)。
然后,在当前从左往右数在位置B1…B2的宠物序列反转她们的顺序(1≤B1<B2≤N)。
当宠物们重复这一过程K次后,请对每一个1≤i≤N 输出从左往右数第i头宠物的编号。

输入描述

输入的第一行包含N和K。第二行包含A1和A2,第三行包含B1和B2。

输出描述

在第i行输出晨练结束时从左往右数第i头宠物的编号。

用例输入 1 

7 2
2 5
3 7

用例输出 1 

1
2
4
3
5
7
6

提示

【数据范围】
30%的数据:1≤K≤1000;
100%的数据:1≤K≤10^9;
【样例解释】
初始时,宠物们的顺序从左往右为 [1,2,3,4,5,6,7]。在这一过程的第一步过后,顺序变为 [1,5,4,3,2,6,7]。在这一过程的第二步过后,顺序变为 [1,5,7,6,2,3,4]。再重复这两个步骤各一次可以得到样例的输出。

方法1,暴力傻子都会做

#include <bits/stdc++.h>
using namespace std;
int n,k,a1,a2,b1,b2,a[101];
int main()
{
	cin>>n>>k>>a1>>a2>>b1>>b2;
	for(int i=1;i<=n;i++)
	{
		a[i]=i;
	}
	for(int i=1;i<=k;i++) 
	{
		int j;
		for(j=a1;j<=(a2+a1)/2;j++)
		{
			int x=a[j];
			a[j]=a[a1+a2-j];
			a[a1+a2-j]=x;
		}
		for(j=b1;j<=(b2+b1)/2;j++)
		{
			int x=a[j];
			a[j]=a[b1+b2-j];
			a[b1+b2-j]=x;
		}
	}
	for(int i=1;i<=n;i++) cout<<a[i]<<'\n';
}

时间复杂度:O(kn)。

此方法必然超时,要寻求优化的办法。

我们发现,这道题目其实是有规律的,它在经过数次操作后会变成之前的状态。假设在模拟Q次后重复,则只需要模拟K%Q此就足够了。

时间复杂度为:O(nQ)

方法2:

#include <bits/stdc++.h>
using namespace std;
int n,k,a1,a2,b1,b2,f[101];
int cz(int x)
{
	if (a1<=x&&x<=a2) x=a1+a2-x;
	if (b1<=x&&x<=b2) x=b1+b2-x;
	return x;
}
int main()
{
	cin>>n>>k>>a1>>a2>>b1>>b2;
	for(int i=1;i<=n;++i) 
	{
		int p=1,q=cz(i);
		while(q!=i){
			p++;
			q=cz(q);
		}
		int g=k%p;
		for (int j=0;j<g;++j) q=cz(q);
		f[q]=i;
	}
	for(int i=1;i<=n;++i) cout<<f[i]<<'\n';
}

由于本人是小学生,讲解不足之处,敬请谅解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值