1. 程式人生 > 其它 >Auto X2021 K Increasing Sequence

Auto X2021 K Increasing Sequence

還是姿勢水平不太行,這道題其實很簡單。

很容易發現最後的序列一定是一個上升序列,並且值域是\(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;
}