題目大意:生成一個數組,有兩種操作,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;
}