http://acm.csu.edu.cn:20080/csuoj/problemset/problem?pid=2214
有一个1到N的自然数序列1,2,3,...,N-1,N。
我们对它进行M次操作,每次操作将其中连续的一段区间 [Ai,Bi][Ai,Bi] (即第Ai个元素到第Bi个元素之间的一段)取出,然后插入到剩下的第Ci个元素的后面,如果Ci=0,表示插入到最左端。
现在,M次操作完后,有K个询问,每个询问Pi表示询问最终第Pi个元素是几。你的任务是写一个程序,依次回答这K个询问。
第一行三个数,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;
输出共K行,为每次询问的答案。
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
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即为答案,依次输出即可
#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\n", x);
}
}
/**********************************************************************
Problem: 2214
User: Artoriax
Language: C++
Result: AC
Time:284 ms
Memory:2140 kb
**********************************************************************/
至此所有寒假集训选拔写过的题的题解补完了,赶快开始补寒假集训的题解了,不能再划水了
原文:https://www.cnblogs.com/artoriax/p/10372535.html