题目链接
http://acm.csu.edu.cn:20080/csuoj/problemset/problem?pid=2214
题目
Description
有一个1到N的自然数序列1,2,3,...,N-1,N。
我们对它进行M次操作,每次操作将其中连续的一段区间 [Ai,Bi][Ai,Bi] (即第Ai个元素到第Bi个元素之间的一段)取出,然后插入到剩下的第Ci个元素的后面,如果Ci=0,表示插入到最左端。
现在,M次操作完后,有K个询问,每个询问Pi表示询问最终第Pi个元素是几。你的任务是写一个程序,依次回答这K个询问。
Input
第一行三个数,N,M,K。
接下来M行,每行三个整数Ai,Bi,Ci。
接下来K行,每行一个正整数Pi。
1<=N<=(10^9),1<=M<=(10^4),1<=K<=1000,1<=Ai<=Bi<=N,0<=Ci<=N-(Bi-Ai+1),1<=Pi<=N;
Output
输出共K行,为每次询问的答案。
Sample Input
13 3 13
6 12 1
2 9 0
10 13 8
1
2
3
4
5
6
7
8
9
10
11
12
13
Sample Output
6
7
8
9
10
11
12
2
3
4
5
13
1
题解
由于k,m都很小,所以我们可以考虑离线的思想离线的思想,对于每一次询问,从m到1把区间平移操作恢复。我们要知道的是最后序列的第x个数,那么我们可以算出不做最后一次平移前x是第几个位置,这样倒退到第一次就是一开始x所在的位置,也就是x所对应的数,输出答案即可。
考虑一下怎么算,有两种情况(c[j] ge a[j])时,我们把(a[j]...b[j])移动到(c[j])后面,此时若x在(a[j],c[j])之间,那么他就会向后移动(b[j]-a[j]+1)个数,如果它在(c[j]+1,c[j]+b[j]-a[j]+1)之间,那么设这次位置是x,恢复平移后位置为y,那么(a[j]+(x-c[j])-1=y),即x+=a[j]-c[j]-1。其他情况x不变
若(c[j]<a[j]),此时若x在(c[j]+1,c[j]+b[j]-a[j]+1)之间,那么x+=a[j]-c[j]-1,若x处在(c[j]+1+b[j]-a[j]+1,b[j])之间,那么(x=c[j]+x-(c[j]+b[j]-a[j]+1))即x+=a[j]-b[j]-1。
一直倒推到1即为答案,依次输出即可
AC代码
#include<bits/stdc++.h>
#define N 10050
using namespace std;
int a[N], b[N], c[N];
typedef long long ll;
int main() {
int n, m, k;
scanf("%d%d%d", &n, &m, &k);
for (int i = 1; i <= m; i++) {
scanf("%d%d%d", &a[i], &b[i], &c[i]);
}
for (int i = 1; i <= k; i++) {
ll x;
scanf("%lld", &x);
for (int j = m; j >= 1; j--) {
if (c[j] >= a[j]) {
if (x >= a[j] && x <= c[j]) {
x += b[j] - a[j] + 1;
}
else if (x >= c[j] + 1 && x <= c[j] + b[j] - a[j] + 1) {
x += a[j] - c[j] - 1;
}
}
else {
if (x >= c[j] + 1 && x <= c[j] + b[j] - a[j] + 1) {
x += c[j] + 1 + a[j] - c[j] - 1 - 1 - c[j];
}
else if (x >= c[j] + b[j] - a[j] + 1 + 1 && x <= b[j]) {
x -= (b[j] - a[j] + 1);
}
}
}
printf("%d
", x);
}
}
/**********************************************************************
Problem: 2214
User: Artoriax
Language: C++
Result: AC
Time:284 ms
Memory:2140 kb
**********************************************************************/
结语
至此所有寒假集训选拔写过的题的题解补完了,赶快开始补寒假集训的题解了,不能再划水了