核心大事实1:对于查询的点k对应的值一定是某个操作过后的最后一个值
核心大事实2:对于操作前数组长度大于k的都不用考虑
核心小事实:点k有两种情况
1.点k的位置在两次操作之间(乘法)
2.点k的位置恰好位于某次操作后的最后一个点(乘法和加法都有可能)
代码构建以此展开
1.要不断地回溯操作,直到找到事实2
2.记录每次操作后数组的长度和最后一个值
code
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll last[1000005]={0};
ll len[100005]={0};
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
ll t;
cin>>t;
while(t--)
{
ll n,q;
cin>>n>>q;
for(ll i=1;i<=n;i++)
{
ll op,x;
cin>>op>>x;
if(op==1)
{
last[i]=x;
len[i]=min(len[i-1]+1,(ll)2e18);
}
else
{
last[i]=last[i-1];
if((ll)2e18/(x+1)<len[i-1]) len[i]=2e18;//防止溢出
else len[i]=len[i-1]*(x+1);
}
}
while(q--)
{
ll k;
cin>>k;
ll times=lower_bound(len+1,len+n+1,k)-len;//如果k点是在某次加法后诞生的,那么一步到位
while(k!=len[times])
{
k=(k-1)%len[times-1]+1;//说明它在乘法之间,回溯等价于在上一步乘法的模数位置
times=lower_bound(len+1,len+n+1,k)-len;//有点像dp?递归?
}
cout<<last[times]<<" ";
}
cout<<endl;
}
return 0;
}
标签:last,ll,cin,len,times,Array,Repetition,乘法
From: https://www.cnblogs.com/pure4knowledge/p/17970888