璟雯院

珺璟如晔,雯华若锦

用户工具

站点工具


icpc:problems:919d_array_repetition
problems
名称Array Repetition
题目编号919D
题目链接codeforces.com/…
来源CodeForces
算法分类数学, 二分
难易程度小有难度

Array Repetition

其实自己想到这道题怎么做了,但是我写的方法TLE,核心思路是一致,还是std写的更简洁一点。故还是呈现std的写法吧。

想法

认真读题可知,1操作为加1个数,2操作为将整个序列倍增。之后求序列中第k个值。

先考虑倍增情况,倍增将区间分成了$x+1$个区间长度的一致的区间,第$k$个值,可通过对区间长度取余,将$k$缩小,使得范围缩小。

记录每个操作的最后一个值,并记录每个操作后序列的长度。需要注意序列可能非常长(超过`long long int`范围),但查询不超过`long long int`范围,故处理时需要处理上限。

二分找到大于k的位置,当序列长度与k一致时,答案为最后一个值,否则对k进行缩减。需要特判余数为0的情况。

代码实现

#include<cstdio>
#include<cstring>
 
int n, q;
 
void solve() {
	scanf("%d %d", &n, &q);
	int lst[n+10];
	long long int s[n+10];
	memset(lst, 0, sizeof(lst));
	memset(s, 0, sizeof(s));
	for(int i=1; i<=n; i++) {
		int type, x;
		scanf("%d %d", &type, &x);
		if(type == 1) {
			lst[i] = x;
			s[i] = s[i-1] + 1;
		}
		else {
			lst[i] = lst[i-1];
			s[i] = ((x + 1) > 2e18 / s[i-1]) ? (long long)2e18: s[i-1]*(x+1);
		}
	}
	for(int i=1; i<=q; i++) {
		long long int temp;
		scanf("%lld", &temp);
		while(temp > 0) {
			int l=1, r=n, mid;
			while(l < r) {
				mid = (l + r) >> 1;
				if(s[mid] < temp)
					l = mid+1;
				else
					r = mid;
			}
			if(s[l] == temp) {
				printf("%d%c", lst[l], " \n"[i==q]);
				break;
			}
			if(temp % s[l-1] == 0) {
				printf("%d%c", lst[l-1], " \n"[i==q]);
				break;
			}
			temp = temp % s[l-1];
		}
	}
	return ;
}
 
int main() {
	int T;
	scanf("%d", &T);
	while(T--) {
		solve();
	}
	return 0;
}
/app/www/public/data/pages/icpc/problems/919d_array_repetition.txt · 最后更改: 2024/01/19 06:55 由 温婕莺