JZOJ 3162. 【GDOI2013模拟2】旋转 (Standard IO)
题目
Description
Alice和Bob发明了一个新的旋转游戏。首先,Bob给定
N
N
N个数组成的序列,并把该序列平均分配成若干个块,每块正好包含
K
K
K个数(
K
K
K能整除
N
N
N)。第一块由第
1
1
1到第
K
K
K个数构成,第二块由第
K
+
1
K+1
K+1个数到第
2
K
2K
2K个数构成,以此类推。
接着,Bob要求Alice对这个序列进行一系列操作,操作有以下两种:
1.把每块里面的数向左或右旋转
X
X
X个位置;
2.把整个序列向左或向右旋转
X
X
X个位置。
注意操作2会改变每一块里面的数。
在执行完一系列操作后,Alice把最终的序列告诉了Bob。Bob的任务就是找到初始序列。
Input
第一行输入三个正整数:序列的长度
N
(
1
≤
N
≤
100
,
000
)
N(1≤N≤100,000)
N(1≤N≤100,000),每一块的大小
K
(
1
≤
K
≤
100
,
000
)
K(1≤K≤100,000)
K(1≤K≤100,000),操作次数
Q
(
1
≤
Q
≤
100
,
000
)
Q(1≤Q≤100,000)
Q(1≤Q≤100,000)。
接下来
Q
Q
Q行,每行包含两个整数:操作种类
A
(
1
≤
A
≤
2
)
A(1≤A≤2)
A(1≤A≤2)和旋转位数
X
(
−
100
,
000
≤
X
≤
100
,
000
)
X(-100,000≤X≤100,000)
X(−100,000≤X≤100,000),其中负数表示向左旋转,整数表示向右旋转。
最后一行输入
N
N
N个数
Z
i
(
0
≤
Z
i
≤
100
,
000
)
Z_i(0≤Z_i≤100,000)
Zi(0≤Zi≤100,000)表示最终序列。
Output
一行输出初始序列。
Sample Input
输入1:
4 2 2
2 2
1 1
3 2 1 0
输入2:
8 4 4
1 3
1 15
1 -5
2 -1
6 10 14 19 2 16 17 1
输入3:
9 3 5
1 1
2 -8
2 9
1 1
2 -4
3 1 8 7 4 5 2 6 9
Sample Output
输出1:
0 1 2 3
输出2:
6 10 14 1 2 16 17 19
输出3:
5 3 6 9 7 1 8 2 4
Data Constraint
40%的数据满足
N
≤
100
N≤100
N≤100.
70%的数据满足
K
≤
100
K≤100
K≤100.
题解
- 显然这题需要从后往前退,方向全部相反。
- 如果每个位置都进行一遍计算,时间复杂度是 O ( N K ) O(NK) O(NK)的,时超!
- 不妨把 N N N个数排成 K K K行的形式,
- 如 1 − 12 1-12 1−12的排列, K = 3 K=3 K=3:
- 1 4 7 10
- 2 5 8 11
- 3 6 9 12
- 若进行 1 1 1操作, X = 2 X=2 X=2:
- 2 5 8 11
- 3 6 9 12
- 1 4 7 10
- 若进行 2 2 2操作, X = 7 X=7 X=7:
- 6 9 12 3
- 7 10 1 4
- 8 11 2 5
- 观察可以发现,
- 不管怎么操作,原本在同一行的数还在同一行,而且顺序是一定的,只是开头的位置变了。
- 如1 4 7 10进行 2 2 2操作后从第一行到了第二行,顺序变成7 10 1 4.
- 行与行之间的顺序也是一定的,只是第一行的位置变了。
- 既然如此。我们如果知道了第一行的位置和每一行开头的位置,就可以推出整个矩阵,从而得到答案。
- 现在来分情况讨论:
- 操作 1 1 1,
- 很显然,不会影响每一行开头的位置,第一行的位置增加 X X X(注意是循环的,到了第 K K K行以后就是第一行)。
- 操作 2 2 2,
- 第一行的位置也是增加了 X X X,
- 那么每一行的开头呢?
- 情况一:如果 K ∣ X K|X K∣X,那么开头位置集体右移 X / K X/K X/K位,
- 如上面的例子, X = 6 X=6 X=6,
- 7 10 1 4
- 8 11 2 5
- 9 12 3 6
- (是不是非常整齐!!!)
- 情况二:否则前 X m o d K Xmod K XmodK行右移 X / K + 1 X/K+1 X/K+1位,其余右移 X / K X/K X/K位,
- 如上面的例子, X = 2 X=2 X=2,
- 11 2 5 8
- 12 3 6 9
- 1 4 7 10
- (先把第一行的位置变到了第三行,然后前两行开头右移了一位,其余右移了零位。
- 但不能每一行地去更新开头的位置,
- 因为每次都是一段区间的修改,所以可以用差分。
- 具体细节简单推一下!
代码
#include<cstdio>
#include<cstring>
using namespace std;
#define N 100010
struct
{
int x,y;
}a[N];
int b[N],c[N],d[N],ans[N];
int main()
{
int n,k,q,i,j,x,y;
scanf("%d%d%d",&n,&k,&q);
for(i=1;i<=q;i++)
{
scanf("%d%d",&a[i].x,&a[i].y);
a[i].y=-a[i].y;
if(a[i].x==1) a[i].y=(a[i].y%k+k)%k; else a[i].y=(a[i].y%n+n)%n;
}
for(i=1;i<=n;i++) scanf("%d",&b[i]);
int fi=1;
for(i=q;i;i--)
{
x=a[i].x,y=a[i].y;
fi=(fi+y-1)%k+1;
if(x==2)
{
int l=y/k,t=y%k;
if(t)
{
int h=(k-fi+1)%k+1;
if(h+t-1<=k)
{
c[h+t]--;
c[1]+=l;
c[h]++;
}
else
{
c[1]+=l+1;
c[(h+t)%k]--;
c[h]++;
}
}
else c[1]+=l;
}
}
d[0]=0;
for(i=1;i<=k;i++) d[i]=((d[i-1]+c[i])%(n/k)+n/k)%(n/k);
int l=fi;
for(i=1;i<=k;i++)
{
for(j=0;j<n/k;j++)
ans[((d[i]+j)%(n/k))*k+l]=b[i+j*k];
l=l%k+1;
}
for(i=1;i<=n;i++) printf("%d ",ans[i]);
return 0;
}