• CF1175F The Number of Subpermutations(单调栈,ST表)


    给出一个数组\(a\),若子串\(a[l,r]\)满足\([1,r-l+1]\)各出现一次,则称其为这个数组的一个子排列。

    求这个数组的子排列个数。

    做法:

    观察到一个子区间\([l,r]\)是一个排列,等价于:

    \([l,r]\)没有重复的数字。

    \([l,r]\)中的最大值为\(r-l+1\)

    用单调栈处理出每个数作为最大值的左右端点。

    那么以这个数为最大值的区间长度是固定的,且这个区间得覆盖这个数这个位置。

    可以证明,这类区间的数量取决于这个数左右区间的较短的那个,所以暴力枚举覆盖这个数并以这个数为最大值的区间即可。

    然后,如何判断一个区间没有重复的数字?

    问题转化为这个区间内是否有一个数字出现了两次。

    对每个数维护一个前驱出现位置,对这个区间询问前驱出现位置的最小值即可。

    如果最小值>=l,说明有数字出现了两次。

    查询最小值上ST表即可。

    时间复杂度\(O(nlogn)\)

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=3e5+10;
    int n,a[maxn];
    stack<int> st;
    int L[maxn],R[maxn],pre[maxn],mp[maxn];
    int dp[maxn][20],mm[maxn];
    void initRMQ (int n) {
    	mm[0]=-1;
    	for (int i=1;i<=n;i++) {
    		mm[i]=((i&(i-1))==0)?mm[i-1]+1:mm[i-1];
    		dp[i][0]=pre[i];
    	}
    	for (int j=1;j<=mm[n];j++) {
    		for (int i=1;i+(1<<j)-1<=n;i++) {
    			dp[i][j]=max(dp[i][j-1],dp[i+(1<<j-1)][j-1]);
    		}
    	}
    }
    int rmq (int x,int y) {
    	int k=mm[y-x+1];
    	return max(dp[x][k],dp[y-(1<<k)+1][k]);
    }
    int main () {
    	scanf("%d",&n);
    	for (int i=1;i<=n;i++) scanf("%d",a+i);
    	for (int i=1;i<=n;i++) L[i]=0,R[i]=n+1;
    	for (int i=1;i<=n;i++) {
    		while (st.size()) {
    			int u=st.top();
    			if (a[u]>=a[i]) {
    				L[i]=u;
    				break;
    			}
    			st.pop();
    		}
    		st.push(i);
    	}
    	while (st.size()) st.pop();
    	for (int i=n;i>=1;i--) {
    		while (st.size()) {
    			int u=st.top();
    			if (a[u]>a[i]) {
    				R[i]=u;
    				break;
    			}
    			st.pop();
    		}
    		st.push(i);
    	}
    	for (int i=1;i<=n;i++) {
    		if (!mp[a[i]]) {
    			mp[a[i]]=i;
    			pre[i]=0;
    		}
    		else {
    			pre[i]=mp[a[i]];
    			mp[a[i]]=i;
    		}
    	}
    	initRMQ(n);
    	int ans=0;
    	for (int i=1;i<=n;i++) {
    	//	printf("%d %d %d\n",L[i]+1,R[i]-1,a[i]);
    		int x=i-L[i];
    		int y=R[i]-i;
    		int len=a[i];
    		if (x<y) {
    			for (int j=L[i]+1;j<=i;j++) {
    				if (j+len-1<i||j+len-1>=R[i]) continue;
    				int l=j,r=j+len-1;
    				if (rmq(l,r)<l) {
    				//	printf("%d %d\n",l,r);
    					ans++;
    				}
    			}
    		}
    		else {
    			for (int j=i;j<=R[i]-1;j++) {
    				if (j-len+1<=L[i]||j-len+1>i) continue;
    				int l=j-len+1,r=j;
    				if (rmq(l,r)<l) {
    				//	printf("%d %d\n",l,r);
    					ans++;
    				}
    			}
    		}
    	}
    	printf("%d\n",ans);
    }
  • 相关阅读:
    Memcached通信协议
    quartz在集群环境下的最终解决方案
    在中间层 .NET 应用程序中通过授权管理器使用基于角色的安全
    微软MVC框架实战:开源的JS库Knockout
    EL表达式
    Hadoop安装配置
    Memcached安装
    Maven对不同的测试环境用不同的参数进行打包
    项目管理案例:赢与非输之别
    十年WEB技术发展历程
  • 原文地址:https://www.cnblogs.com/zhanglichen/p/15524788.html
Copyright © 2020-2023  润新知