D. Array Repetition

原题链接

分析

1.如果某次操作之后,数组的长度大于等于k,我们把这样的操作叫最后操作,且最后操作之后的操作都不用考虑,因为不会影响前面的数组,我们把这样
2.最后操作只有两种,一种是加法,一种是乘法
如果是加法,那么k一定等于此时数组的长度,对应的值一定是这次加法加上去的值,也就是末尾值
如果是乘法,那么分为两种一种是数组的长度恰好等于k,那么这次k对应的值也一定是这次操作过后的末尾值
如果k小于数组的长度,那么递归?分治?dp?反正k的值和上一次操作过后的数组的第k mod len[now1]位等价

构建

记录每次操作后的数组长度和末尾值,循环找出数组长度大于等于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;
}

posted @   纯粹的  阅读(17)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· Manus的开源复刻OpenManus初探
· AI 智能体引爆开源社区「GitHub 热点速览」
· 从HTTP原因短语缺失研究HTTP/2和HTTP/3的设计差异
· 三行代码完成国际化适配,妙~啊~
点击右上角即可分享
微信分享提示