P14977 [USACO26JAN1] Lineup Queries S(题解)

标题

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)个独立的查询,每个查询属于以下两种类型之一:

  1. 在时刻 t t t 刚结束时,奶牛 c c c 在什么位置( 0 ≤ c ≤ t ≤ 10 18 0\le c\le t\le 10^{18} 0≤c≤t≤1018)?
  2. 在时刻 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

*/
相关推荐
HalvmånEver1 小时前
Linux:信号保存下(信号二)
linux·运维·服务器·c++·学习·信号
夜勤月1 小时前
拒绝线程死锁与调度延迟:深度实战 C++ 内存模型与无锁队列,构建高并发系统级中枢
java·c++·spring
狐572 小时前
2026-01-22-牛客每日一题-二进制不同位数
算法·牛客
十八岁讨厌编程2 小时前
【算法训练营 · 二刷总结篇】链表、哈希表部分
算法·链表·散列表
西瓜泡泡奶2 小时前
代码随想录算法Day13|(二叉树part3)110.平衡二叉树、257. 二叉树的所有路径、404.左叶子之和、222.完全二叉树的节点个数
数据结构·算法·二叉树·平衡二叉树·完全二叉树·二叉树路径·左叶子之和
Remember_9932 小时前
【LeetCode精选算法】前缀和专题一
java·开发语言·数据结构·算法·leetcode·eclipse
孞㐑¥2 小时前
算法—双指针
开发语言·c++·经验分享·笔记·算法
承渊政道2 小时前
C++学习之旅【C++List类介绍—入门指南与核心概念解析】
c语言·开发语言·c++·学习·链表·list·visual studio
带土12 小时前
11. C++封装
开发语言·c++