• SP744 LPERMUT


    SP744 LPERMUT - Longest Permutation

    找到一个最长的子段,满足其重排后是 (1,2,3,4...k) ,其中 (k) 是子段长度。

    一道思维题。

    首先我们考虑找到这样的段的性质:序列长度为 (k) 且互不相同。

    然后我们可以推出一个结论:这个序列中一定只包含一个某一个数

    于是我们原数列中的 1 就相当于是把原数列分成了很多的段,于是如果我们可以每次以 1 为起点,然后向两边中的某一边扫一遍的话,就能够 (O(n)) 解决这个问题。

    但是我们势必是要枚举两边的,这样做就是 (O(n^2)) 的了,于是我们可以考虑枚举一边,然后 (O(1)) 算另一边最长对应可以到达的位置。

    这个该怎么算呢,我们假设目前匹配到的左端点是 (pos) ,然后当前右端点是 (i) (枚举 (i)),然后枚举下一个 (i) 的时候,答案的 (pos) 单调不增(如果此时会发生 (pos++) 了就代表遇到了两个同样的了。)。

    那么一个点对于另外一个点的增加/减少有单调性,很明显就是双指针扫一遍了。

    于是最后我们的复杂度为 (O(n))

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    template <typename T>
    inline void read(T &x){
    	x=0;char ch=getchar();bool f=false;
    	while(!isdigit(ch)){if(ch=='-'){f=true;}ch=getchar();}
    	while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    	x=f?-x:x;
    	return ;
    }
    template <typename T>
    inline void write(T x){
    	if(x<0) putchar('-'),x=-x;
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    	return ;
    }
    const int N=3e5+5;
    int n,a[N],ans;
    int posl[N],posr[N],pos[N],Max[N],Maxpos[N];
    void work(int s,int L,int R){
    	if(ans==0)ans=1;
    	Max[s]=a[s];
    	for(int i=s-1;i>=L;i--) Max[i]=max(Max[i+1],a[i]);
    	for(int i=s+1;i<=R;i++) Max[i]=max(Max[i-1],a[i]);
    	Maxpos[s]=posl[s];
    	for(int i=s-1;i>=L;i--) Maxpos[i]=max(Maxpos[i+1],posl[i]);
    	for(int i=s+1;i<=R;i++) Maxpos[i]=max(Maxpos[i-1],posl[i]);
    	for(int i=s-1;i>=L;i--){
        	if(Maxpos[i]>=i) continue;
        	int len=Max[i],r=i+len-1;
        	if(r>R) continue;
        	if(Maxpos[r]>=i||Max[r]>=Max[i]) continue;
        	if(len>ans) ans=len;
    	}
    	for(int i=s+1;i<=R;i++){
    		if(Maxpos[i]>=s) continue;
    		int len=Max[i],l=i-len+1;
    		if(l<L) continue;
    		if(Maxpos[l]>=l||Maxpos[i]>=l||Max[l]>=Max[i]) continue;
    		if(len>ans) ans=len;
    	}
    	return ;
    }
    int main(){
    	read(n);
    	for(int i=1;i<=n;i++) read(a[i]);
    	for(int i=1;i<=n;i++) posl[i]=pos[a[i]],pos[a[i]]=i;
    	for(int i=1;i<=n;i++) pos[i]=n+1;
    	for(int i=n;i>=1;i--) posr[i]=pos[a[i]],pos[a[i]]=i;
    	for(int i=1;i<=n;i++) if(a[i]==1) work(i,posl[i]+1,posr[i]-1);
    	write(ans);
    	return 0;
    }
    
  • 相关阅读:
    EF关联
    nopcommerce v3.9中文包
    Android Activity切换与Activity间数据交互
    C#多线程的用法9-Semaphore
    C#多线程的用法8-线程间的协作AutoResetEvent
    C#多线程的用法7-线程间的协作ManualResetEvent
    C#多线程的用法6-线程间的协作Mutex
    C#多线程的用法5-线程间的协作Monitor
    C#多线程的用法4-线程间的协作lock快捷方式
    C#多线程的用法3-线程间的协作Join
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14683674.html
Copyright © 2020-2023  润新知