Educational Codeforces Round 100 (Rated for Div. 2)D. Pairs(选定取min剩余取max组成给定集合)
题:https://codeforces.com/contest/1463/problem/D
题意:从1~2*n之间随意取出n个pair,选定其中x个取出其中的最小值,选定其中(n-x)取出其中的最大值,组成n个数恰好是给定的set(这里记为f1数组),问0<=x<=n,有多少个取值是满足题意的(n<=2e5)。
分析:
- 单单考虑取最小值,看最大能取到多少个pair使得这些最小值都在set中;
- 设f2数组为没有出现在set中的数(f1和f2数组升序),那么最大能取到的就是f1的前段和f2的后段组成pair,且具有单调性,那么可以用二分求出最大值记为maxL;
- 取最大值同理,记为minR,那么合法的x就是在[n-minR+1,maxL]之间取(因为要保证选定pair取min的同时剩余的pair要取max最终能组成题目给的set),答案就是这个区间长度。
#include<bits/stdc++.h> using namespace std; #define pb push_back #define MP make_pair #define UM unordered_map typedef long long ll; const int mod=1e9+7; const int inf=0x3f3f3f3f; const ll INF=1e18; #define pi 3.1415926535898 #define DEC (pi/180) const static int M=4e5+5; int vis[M],f1[M<<1],f2[M<<1]; void pn(){ puts("NO"); } void py(){ puts("YES"); } int main(){ int T; scanf("%d",&T); while(T--){ int n; scanf("%d",&n); for(int i=1;i<=2*n;i++) vis[i]=0; for(int x,i=1;i<=n;i++){ scanf("%d",&x); vis[x]=1; } int tot1=0,tot2=0; for(int i=1;i<=2*n;i++){ if(vis[i]==1) f1[++tot1]=i; else f2[++tot2]=i; } int L=0,R=n,maxL=0; while(L<=R){ int midd=(L+R)>>1; int ok=1; for(int i=1;i<=midd;i++) if(f1[i]>f2[n-midd+i]) ok=0;///要最小值为标记过的值 if(ok){ L=midd+1; maxL=midd; } else R=midd-1; } L=0,R=n; int minR=n; while(L<=R){ int midd=(L+R)>>1; int ok=1; for(int i=1;i<=midd;i++) if(f2[i]>f1[n-midd+i]) ok=0;///要最大值为标记过的值 if(ok){ L=midd+1; minR=midd; } else R=midd-1; } printf("%d\n",maxL-(n-minR)+1);///相交区间的长度 } return 0; }