cf1143E 倍增好题!

一开始感觉用莫队可以搞一下,但是看了题解才发现这题其实是倍增套路题

把排列转换成nxt数组,然后倍增dp[i][j]表示第i个数后面有(1<<j)个数的最靠左的区间

然后从右往左扫一次即可

#include<bits/stdc++.h>
using namespace std;
#define maxn 200005
int dp[maxn][20],last[maxn],nxt[maxn],ans[maxn],a[maxn],b[maxn],n,m,t;
//dp[i][j]表示第i个数开始的后面(1<<j)个数的位置 
int main(){
    cin>>n>>m>>t;
    for(int i=1;i<=n;i++)cin>>a[i];
    for(int i=1;i<=n;i++)nxt[a[i-1]]=a[i];    
    nxt[a[n]]=a[1];
    for(int i=1;i<=m;i++)cin>>b[i];
    for(int i=1;i<=n;i++)last[i]=m+1;
    for(int i=0;i<=19;i++)dp[m+1][i]=m+1;
    ans[m+1]=m+1;
    for(int i=m;i>=1;i--){
        dp[i][0]=last[nxt[b[i]]];
        last[b[i]]=i;
        for(int j=1;j<=19;j++)dp[i][j]=dp[dp[i][j-1]][j-1];
        int cnt=n-1,pos=i;
        for(int j=19;j>=0;j--)
            if(cnt >= (1<<j))
                cnt-=(1<<j),pos=dp[pos][j];
        ans[i]=min(ans[i+1],pos);
    }
    for(int i=1;i<=t;i++){
        int l,r;
        cin>>l>>r;
        if(ans[l]<=r)cout<<"1";
        else cout<<"0";
    }
}

 

转载于:https://www.cnblogs.com/zsben991126/p/10638911.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值