题目大意:生成一个数组,有两种操作,1 x 表示在数组后加上 x ,2 l c 表示将此时数组的前 l 个复制 c 次加到数组末尾。最后升序查询数组元素
思路:显然,如果不停的复制的话数组是存不下的。最多有m(1e5)次操作,也就是数组最多有1e5个数是新添加的,剩下的都是复制出来的,那么只要将复制的部分折叠式地存为1个元素就行了。第一次使用 lower_bound(a,a+n,x)- a 表示返回a中第一个大于等于x的元素地址,代替了二分很方便啊。之前写直接暴力遍历数组,结果 t 在了31,才想到了用二分搜索。果然,我还是太弱了。(这题写了好久,终于a了,好想哭啊啊啊)
#include <bits/stdc++.h>
#define manx 100005
typedef long long ll;
using namespace std;
ll m,k,c;
ll a[manx];
bool f[manx];
ll len=1,n,x,num[manx];
ll solve(ll x)
{
ll k=lower_bound(num,num+m+1,x)-num; //返回num中第一个>=x的数的下标
if(f[k]) return a[k];
x = (x-num[k-1]) % a[k]; //第x个和(x-num[k-1])%a[k]个等价
if (x) return solve(x);
else return solve(a[k]);
}
int main()
{
memset(f,true,sizeof(f));
scanf("%I64d",&m);
for (int i=1; i<=m; i++){
scanf("%I64d",&k);
if(k==1){
scanf("%I64d",&a[i]);
num[i]=len++;
}
else if (k==2){
scanf("%I64d%I64d",&a[i],&c);
len+=a[i]*c;
f[i]=false; //表示复制折叠部分
num[i]=len-1;
}
}
scanf("%I64d",&n);
ll i=1;
while(n--){
scanf("%I64d",&x);
while(i<=m){ //升序查询(后来觉得这步没有必要,直接solve())
if(num[i] == x && f[i]){
printf("%I64d",a[i]);
n ? printf(" "):printf("\n");
i++;
break;
}
else if(num[i] >= x){
ll ans=solve(x);
printf("%I64d",ans);
n ? printf(" "):printf("\n");
break;
}
else i++;
}
}
return 0;
}