P7647 [COCI2012-2013#5] ROTIRAJ
建议重写题面
题意:
长度为
第一类操作为每个子序列左/右移
第二类操作为所有位置左/右移
然后两类操作均为循环移位,即1234左移后变为2341
给出
Part1
观察到该操作具有可逆性,因此只需要把
Part2
考虑根号分治,当
显然不能直接循环移位,因此考虑维护块内真实的开头指针
整体左移则是上一块的开头会放入这一块的结尾,并且这一块的开头会消失,可以直接将上一块开头放入这一块开头并将指针移动,整体右移同理.
若
复杂度为
Part3
考虑我们 第一块开头是什么数组的维护
而这个数组可以记录
那么我们每次整体移动操作,就仅仅相当于对于
而这个过程显然可以用差分数组来优化!
因此本题也就做完了,对于二操作直接差分,一操作只是简单的循环位移而已
代码
#include<bits/stdc++.h>
#define pb push_back
#define vi vector<int>
#define ll long long
using namespace std;
const int MAXN = 1e5 + 7;
int n, k, q;
int typ[MAXN], x[MAXN], a[MAXN];
ll pos[MAXN];
vi b[MAXN];
inline void IO() {
scanf("%d%d%d", &n, &k, &q);
for(int i = 1; i <= q; ++i) {
scanf("%d%d", &typ[i], &x[i]);
x[i] = -x[i];
}
reverse(typ + 1, typ + q + 1);
reverse(x + 1, x + q + 1);
for(int i = 0; i < n; ++i) {
scanf("%d", &a[i]);
b[i % k].pb(a[i]);
}
return;
}
inline void solve1() {
int hd = 0;
for(int i = 1; i <= q; ++i) {
if(typ[i] == 1) {
hd = ((hd - x[i]) % k + k) % k;
} else {
if(x[i] < 0) {
int q = -x[i];
if(q <= k - hd) {
pos[hd]++;
pos[hd + q]--;
} else {
--q;
pos[hd]++;
q -= k - hd;
if(q >= k) {
pos[0] += q / k;
q = q % k;
}
pos[0]++;
pos[q + 1]--;
}
} else {
int q = x[i];
int tl = (hd - 1 + k) % k;
if(q <= tl) {
pos[tl - q + 1]--;
pos[tl + 1]++;
} else {
--q;
pos[0]--;
pos[tl + 1]++;
q -= tl;
if(q >= k) {
pos[0] -= q / k;
q = q % k;
}
pos[k - q]--;
}
}
hd = (hd - x[i] % k + k) % k;
}
}
for(int i = 1; i < k; ++i)pos[i] += pos[i - 1];
for(int i = 0; i < n; i += k) {
for(int j = hd;; j = (j + 1) % k) {
printf("%d ", b[j][(i / k + pos[j] % (n / k) + n / k) % (n / k)]);
if((j + 1) % k == hd)break;
}
}
puts("");
return ;
}
int main() {
IO();
solve1();
return 0;
}