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 由 温婕莺