D. Array Repetition
分析
1.如果某次操作之后,数组的长度大于等于k,我们把这样的操作叫最后操作,且最后操作之后的操作都不用考虑,因为不会影响前面的数组,我们把这样
2.最后操作只有两种,一种是加法,一种是乘法
如果是加法,那么k一定等于此时数组的长度,对应的值一定是这次加法加上去的值,也就是末尾值
如果是乘法,那么分为两种一种是数组的长度恰好等于k,那么这次k对应的值也一定是这次操作过后的末尾值
如果k小于数组的长度,那么递归?分治?dp?反正k的值和上一次操作过后的数组的第\(k \ mod \ len[now-1]\)位等价
构建
记录每次操作后的数组长度和末尾值,循环找出数组长度大于等于k的操作,直到长度等于k,答案就是此时的末尾值
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;
}

浙公网安备 33010602011771号