
标题
P14977 [USACO26JAN1] Lineup Queries S
题目描述
有一队奶牛,初始时(即时刻 t = 0 t = 0 t=0)只有奶牛 0 0 0 在位置 0 0 0(这里,一头奶牛在位置 k k k 表示它前面有 k k k 头奶牛)。在时刻 t t t( t = 1 , 2 , 3 , ... t=1,2,3,\dots t=1,2,3,...),位置 0 0 0 的奶牛移动到位置 ⌊ t / 2 ⌋ \lfloor t/2\rfloor ⌊t/2⌋,位置 1 ... ⌊ t / 2 ⌋ 1\dots \lfloor t/2\rfloor 1...⌊t/2⌋ 上的每头奶牛向前移动一个位置,并且奶牛 t t t 加入到队列的末尾(位置 t t t)。
回答 Q Q Q( 1 ≤ Q ≤ 10 5 1\le Q\le 10^5 1≤Q≤105)个独立的查询,每个查询属于以下两种类型之一:
- 在时刻 t t t 刚结束时,奶牛 c c c 在什么位置( 0 ≤ c ≤ t ≤ 10 18 0\le c\le t\le 10^{18} 0≤c≤t≤1018)?
- 在时刻 t t t 刚结束时,位置 x x x 上是哪头奶牛( 0 ≤ x ≤ t ≤ 10 18 0\le x\le t\le 10^{18} 0≤x≤t≤1018)?
输入格式
第一行包含 Q Q Q,表示查询的数量。
接下来的 Q Q Q 行,每行包含三个整数,指定一个查询,格式为 " 1 1 1 c c c t t t" 或 " 2 2 2 x x x t t t"。
输出格式
将每个查询的答案输出在单独一行。
输入输出样例 #1
输入 #1
2
1 4 9
2 2 9
输出 #1
2
4
输入输出样例 #2
输入 #2
22
1 0 9
1 1 9
1 2 9
1 3 9
1 4 9
1 5 9
1 6 9
1 7 9
1 8 9
1 9 9
2 0 9
2 1 9
2 2 9
2 3 9
2 4 9
2 5 9
2 6 9
2 7 9
2 8 9
2 9 9
1 0 1000000000000000000
2 0 1000000000000000000
输出 #2
1
3
0
4
2
5
6
7
8
9
2
0
4
1
3
5
6
7
8
9
483992463350322770
148148148148148148
说明/提示
不同时刻刚结束时的队列排列:
none
t = 0 | 0
t = 1 | 0 1
t = 2 | 1 0 2
t = 3 | 0 1 2 3
t = 4 | 1 2 0 3 4
t = 5 | 2 0 1 3 4 5
t = 6 | 0 1 3 2 4 5 6
t = 7 | 1 3 2 0 4 5 6 7
t = 8 | 3 2 0 4 1 5 6 7 8
t = 9 | 2 0 4 1 3 5 6 7 8 9
在 t = 9 t=9 t=9 刚结束时,奶牛 4 4 4 的位置是 2 2 2,而位置 2 2 2 上的奶牛是 4 4 4。
- 输入 3 3 3: Q ≤ 1000 , t ≤ 100 Q\le 1000, t\le 100 Q≤1000,t≤100
- 输入 4 4 4: t ≤ 5000 t\le 5000 t≤5000
- 输入 5 5 5- 8 8 8:所有查询均为类型 1。
- 输入 9 9 9- 12 12 12:所有查询均为类型 2。
翻译由 DeepSeek V3 完成
思路
观察表。
text
t = 0 | 0.
t = 1 | 0.1.
t = 2 | 1 0.2
t = 3 | 0 1.2.3
t = 4 | 1 2 0.3 4
t = 5 | 2 0 1.3.4 5
t = 6 | 0 1 3 2.4 5 6
t = 7 | 1 3 2 0.4.5 6 7
t = 8 | 3 2 0 4 1.5 6 7 8
t = 9 | 2 0 4 1 3.5.6 7 8 9
发现我打点的位置左下方的每个元素都是在持续向左下"转"的,转到边界就会回到下一行的分界线。画一画发现分界线左下方的点满足 x × 2 − t ≤ 1 x\times2-t\le1 x×2−t≤1,于是我们模拟这个过程即可。
查询一:
对于每个元素,它先不动,之后进入"转",进入转的时间满足 x × 2 − t = 1 x\times2-t=1 x×2−t=1,我们就可以解出它进入转的时间。( x = 0 x=0 x=0 需要特判。)
之后模拟向左下方转的过程,如果在转到 x = 0 x=0 x=0 前会经过查询的时间 t t t,就可以直接输出了。
否则我们算出它转到 x = 0 x=0 x=0 的时间,再算一下几个时间点的上图打点的位置,把它挪过去接着算即可。
查询二:
和查询一相同,不断向右上挪,如果再挪一步会跑出 x × 2 − t ≤ 1 x\times2-t\le1 x×2−t≤1,则停下来。
如果恰好 x × 2 − t = 1 x\times2-t=1 x×2−t=1,那么这个元素会离开"转",直接输出 x x x 即可。最终总会立刻或者 t = 0 t=0 t=0。
代码
代码不是太难,时间复杂度 O ( T × log 2 n ) O(T\times\log_2n) O(T×log2n)。
cpp
#include <bits/stdc++.h>
#define int long long
using namespace std;
// signed main() {
// vector<int> v{0};
// for (int t = 1; t <= 99; t++) {
// v.insert(v.begin() + (t + 2) / 2, v[0]);
// v.erase(v.begin());
// v.push_back(t);
// printf("%2d : ", t);
// for (int i : v) {
// printf("%3d", i);
// }
// cout << endl;
// }
// return 0;
// }
int T, op, x, t;
signed main() {
cin >> T;
while (T--) {
cin >> op >> x >> t;
if (op == 1) {
if (x == 0 && t <= 1) {
cout << "0\n";
continue;
}
if (x >= t / 2 + 1) {
cout << x << '\n';
continue;
}
int nowt = (x ? x * 2 - 1 : 1);
while (1) {
int endt = nowt + x;
if (t <= endt) {
x -= t - nowt;
break;
} else {
nowt = endt + 1;
x = nowt / 2;
}
}
cout << x << '\n';
} else {
while (x * 2 - t < 1) {
int d = 1 - (x * 2 - t);
d /= 3;
t -= d;
x += d;
if (x * 2 - t < 1) {
t--;
x = 0;
}
}
cout << x << endl;
}
}
}
/*
t-- x++
x*2-t<=1
*/