CodeForces 652C Foe Pairs(思维题)
http://codeforces.com/problemset/problem/652/C
给出一个含有n个数的排列,给出m组数对(ai,bi),问n中有多少个区间是不包含任意一个数对的? (1<=n,m<=3e5, 1<=ai,bi<=n, ai≠ bi)
例如:第一组样例:区间[1,3]是含有第一个数对(3,2),区间[1,4]两个数对都包含,所以这两个区间是不计算的。答案是[1,1],[2,2],[3,3],[4,4],[1,2]这5个区间
思路:
用一个数组f[]记录每个位置可以延伸的最大右端点。这样可以根据数组f[],遍历每个位置i,计算以i为左区间而不包含任意数对的区间个数,达到计算全部区间的效果。
先对每个数对的所在左区间更新可达最大右端点。
再从后往前再更新一次,使得左边点的延伸最大右端点一定是 小于等于任意右边点的延伸最大右端点。使得中间不包含任意数对。
代码:
#include<algorithm> #include<cstdio> #include<cstring> #include<queue> #define inf 0x3f3f3f3f using namespace std; typedef long long ll; const int maxn=3e5+100; int f[maxn],p[maxn]; int main() { int n,m,x,y; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { scanf("%d",&x); f[i]=n;//初始化可延伸右端点为n p[x]=i;//记录每个数的位置 } for(int i=1;i<=m;i++) { scanf("%d%d",&x,&y); int l=min(p[x],p[y]);//得到每个数对的左右区间 int r=max(p[x],p[y]); f[l]=min(f[l],r-1);//记录每个左端点可达最大延伸右端点 } for(int i=n-1;i>=1;i--) { f[i]=min(f[i],f[i+1]);//更新每个位置的可达最大右端点 } ll ans=0; for(int i=1;i<=n;i++) ans+=f[i]-i+1;//计算以i为左区间,可以不包含任意数对的区间个数 printf("%lld\n",ans); }