Auto X2021 K Increasing Sequence
阿新 • • 發佈:2021-10-17
還是姿勢水平不太行,這道題其實很簡單。
很容易發現最後的序列一定是一個上升序列,並且值域是\(1-32\)的,很小。
進一步的,我們可以發現,刪數可以隨意刪,只要我們能儘量合成較大的數就行了。
我們可以令\(f[j][i]\)表示從\(j\)開始,要合成一個\(i\),最近會跳到什麼位置。
這個陣列顯然是用來倍增的,我們列舉的時候可以從左向右列舉一下,維護出這個陣列。
對於詢問,直接從右端點向前跳即可。
#include<bits/stdc++.h> #define N 100009 using namespace std; typedef long long ll; int f[N][41]; int n,m,a[N]; inline ll rd(){ ll x=0;char c=getchar();bool f=0; while(!isdigit(c)){if(c=='-')f=1;c=getchar();} while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();} return f?-x:x; } int main(){ int T=rd(); while(T--){ n=rd();m=rd(); for(int i=0;i<=n;++i){ for(int j=0;j<=40;++j)f[i][j]=-1; } for(int i=1;i<=n;++i){ a[i]=rd(); } for(int i=1;i<=40;++i){ int now=-1; for(int j=1;j<=n;++j){ if(a[j]<i){ if(f[j][i-1]!=-1&&f[f[j][i-1]][i-1]!=-1)f[j][i]=f[f[j][i-1]][i-1]; else f[j][i]=now; } else if(a[j]==i)f[j][i]=j-1,now=j-1; else now=-1; } } while(m--){ int l=rd();int r=rd(); int ans=0; for(int i=40;i>=1;--i)if(f[r][i]>=l-1){ ans+=i; r=f[r][i]; } printf("%d\n",ans); } } return 0; }