题目描述
Farmer John 的 N 头奶牛(1≤N≤10^5)站成一排。对于每一个 1≤i≤N,从左往右数第 i 头奶牛的编号为 i。Farmer John 想到了一个新的奶牛晨练方案。他给奶牛们 M 对整数 (L1,R1)…(LM,RM),其中 1≤M≤100。他让她们重复以下包含 M 个步骤的过程 K(1≤K≤10^9)次:
对于从 1 到 M 的每一个步骤i:当前从左往右数在位置 Li…Ri 的奶牛序列反转她们的顺序。
当奶牛们重复这一过程 K 次后,请对每一个 1≤i≤N 输出从左往右数第 i 头奶牛的编号。
输入
输入的第一行包含 N, M 和 K。对于每一个 1≤i≤M,第 i+1 行包含 Li 和 Ri,均为范围在 1…N 内的整数,其中 Li<Ri。
输出
在第 i 行输出指令序列执行了 K 次后奶牛序列中从左往右数第 i 个元素的编号。
样例输入
7 2 2
2 5
3 7
样例输出
1
2
4
3
5
7
6
数据范围限制
测试点 1-2 满足 N=K=100。
测试点 3-5 满足 K≤10^3。
测试点 6-10 没有额外限制。
提示
初始时,奶牛们的顺序从左往右为 [1,2,3,4,5,6,7]。在这一过程的第一步过后,顺序变为 [1,5,4,3,2,6,7]。在这一过程的第二步过后,顺序变为 [1,5,7,6,2,3,4]。再重复这两个步骤各一次可以得到样例的输出。
分析
解题思路
对于初始的序列 1−N 我们可以把它看作数组的位置下标,那么每次操作不就是调换位置,不用管此时在这个位置上的数,也就是我们只要得出进行 M 次操作后第 i 位会换到的位置并标记,每一轮结束后就只用调位置就行了,不用再模拟一遍 M 。
本题的核心思想:把本次的序号转化为下一次的数
例:因为a[1]=2,所以b[1]=a[2]。a和b的下标相同,a数组的2变成a[2]。
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m,k;
int a[35][100001];
/*本题的核心思想:把本次的序号转化为下一次的数
例:因为a[1]=2,所以b[1]=a[2]。a和b的下标相同,a数组的2变成a[2]*/
void change(int x,int y)
{
for(register int i=1;i<=n;i++)
{
a[x][i]=a[y][a[x][i]];
}
return;
}
int main()
{
freopen("swap.in","r",stdin);
freopen("swap.out","w",stdout);
scanf("%d%d%d",&n,&m,&k);
for(register int i=1;i<=n;i++)
{
a[0][i]=a[1][i]=i;
}
for(int i=1;i<=m;i++)
{
int x,y;
scanf("%d%d",&x,&y);
for(register int i=x;i<=(x+y)/2;i++)
{
swap(a[1][i],a[1][x+y-i]);
}
}
for(register int i=2;i<=31;i++)
{
for(register int j=1;j<=n;j++)
{
a[i][j]=a[i-1][j];
}
change(i,i-1);
}
for(register int i=1;i<=n;i++)
{
a[32][i]=a[0][i];
}
int count=1;
while(k!=0)
{
if(k%2!=0)
{
change(32,count);
}
count++;
k=k/2;
}
for(int i=1;i<=n;i++)
{
printf("%d\n",a[32][i]);
}
fclose(stdin);
fclose(stdout);
return 0;
}