2024.11.19 模拟赛

11.19 模拟赛

题目质量点赞!好题!

storm

普及组模拟题

god

有趣的 dp 题

key:考察相对位置设计状态

\(f(i,j)\) 表示考虑后 \(i\) 个操作,经过了相对坐标为 \(j\) 的点的概率。

转移中,如果这一步不动,相对坐标不变;否则,相对坐标整体平移。

答案就是 \(f(n,j)\)

fate

瞎搞贪心题

显然从左到右依次考虑能否放左括号,关键在于判定“同组”的是否合法。

场上用线段树维护后缀和,按照括号匹配的一般思路,要求后缀和最大值不大于 0。

常数较大,卡了一会才过。

题解是一个结论:

合法括号匹配的左括号序列被 \(1,3,5,\dots,2n-1\) 偏序

故考虑给每个左括号匹配一个值,set 维护当前还未匹配的值,每次查询能否匹配即可。

rectangle

容斥 + 扫描线 码力题

将每个矩形看作一个点,有交的矩形之间连边,问题转化为求有多少个 \((i,j,k)\) 的生成子图没有边。

考虑容斥,用所有三元组的数量减去有边的三元组的数量。记有 \(1\) 条边的个数为 \(c_1\)\(2\) 条边的个数为 \(c_2\)\(3\) 条边的个数为 \(c_3\),答案为 \({n \choose 3} - c_1 -c_2 -c_3\)

step1:用度数 \(d_i\) 求出 \(c_1+c_2\)

  • 至少有一条边时(选一个点 \(i\),再选一个与 \(i\) 相连的点 \(j\),再随便选一个点 \(k\)):\(\sum d_i(n-2)=2c_1+4c_2+6c_3\)
  • 至少有两条边时(选一个点 \(i\),再选两个与 \(i\) 相连的点 \(j,k\) ):\(\sum {d_i \choose 2} =c_2+3c_3\)

step2:扫描线求出 \(d_i\)

考虑正常的从左往右扫,此时可以保证横向全都有交,只需考虑纵向。

\((a,b)\) 纵向有交 当且仅当 \(yl_b\le yr_a\)\(yr_b \ge yl_a\)(已知两两不同)

故用 \(\le yr_a\)\(yl\) 数量减去 $< yl_a $ 的 \(yr\) 数量,最后再减掉自己即可。

横向扫描线就是对 \(xl\le xr_a\)\(xr<xl_a\) 分别计算,保证横向有交。

step3:容斥求出 \(c_3\)

考虑在 \(xl\) 最大的位置统计三元组,不妨为 \(i\)

从与 \(i\) 有交的点中选 \(j,k\),再减去 \(j,k\) 不交的情况。

发现此时 \(xl_j\le xl_i\le xr_j\)\(xl_k\le xl_i\le xr_k\),即 \(j,k\) 横向必有交,故只需考虑纵向。

不妨令 \(yr_j<yl_k\),则必有 \(yl_i\le yr_j<yl_k\le yr_i\),可以用线段树维护。

附:线段树维护信息
\((a,b,c)\) 表示区间内有 \(a\)\(yr\)\(b\)\(yl\)\(c\)\(yr<yl\)
合并时 \(a,b\) 直接相加,\(c\) 要加上左边的 \(a\) 乘右边的 \(b\)

#include<bits/stdc++.h>
using namespace std;
#define rep(i,x,y) for(int i=x;i<=y;i++)
#define per(i,x,y) for(int i=x;i>=y;i--)
#define REPG(i,g,x) for(int i=g.head[x];~i;i=g.edge[i].nxt)
#define LL long long
 
template<class T>
inline void read(T &x){
    T s=0,f=1;char c=getchar();
    for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
    for(;isdigit(c);c=getchar()) s=s*10+c-'0';
    x=s*f;
}

const int N=4e5+5;
inline LL c2(LL x){
    return x*(x-1)/2;
}
inline LL c3(LL x){
    return x*(x-1)*(x-2)/6;
}
int limx,limy;
struct bit{
    int c[N];
    inline void upd(int x,int v){
        for(int i=x;i<=limy;i+=(i&-i)) c[i]+=v;
    }
    inline int ask(int x){
        int res=0;
        for(int i=x;i;i-=(i&-i)) res+=c[i];
        return res;
    }
    inline int que(int l,int r){
        return ask(r)-ask(l-1);
    }
}xlyl,xlyr,xryl,xryr,nwyl,nwyr;

namespace seg{
    struct info{
        LL a,b,c;
        info(LL a=0,LL b=0,LL c=0):a(a),b(b),c(c){}
        inline info operator+(const info &x)const{
            return info(a+x.a,b+x.b,c+x.c+x.a*b);
        }
    }ino[2*N];
    int tot;
    int ls[2*N],rs[2*N];
    inline void pushup(int x){
        ino[x]=ino[ls[x]]+ino[rs[x]];
    }
    inline int build(int l,int r){
        int x=++tot;
        if(l==r) return ino[x]=info(0,0,0),x;
        int mid=(l+r)>>1;
        ls[x]=build(l,mid);
        rs[x]=build(mid+1,r);
        return pushup(x),x;
    }
    inline void upda(int x,int l,int r,int p,int v){
        if(l==r) return ino[x].a+=v,void();
        int mid=(l+r)>>1;
        if(p<=mid) upda(ls[x],l,mid,p,v);
        else upda(rs[x],mid+1,r,p,v);
        return pushup(x);
    }
    inline void updb(int x,int l,int r,int p,int v){
        if(l==r) return ino[x].b+=v,void();
        int mid=(l+r)>>1;
        if(p<=mid) updb(ls[x],l,mid,p,v);
        else updb(rs[x],mid+1,r,p,v);
        return pushup(x);
    }
    inline info ask(int x,int l,int r,int s,int t){
        if(l>=s && r<=t) return ino[x];
        int mid=(l+r)>>1;info res(0,0,0);
        if(s<=mid) res=res+ask(ls[x],l,mid,s,t);
        if(t>mid) res=res+ask(rs[x],mid+1,r,s,t);
        return res;
    }
}

int n;
struct rec{
    int xl,xr,yl,yr,du;
}r[N];
int cx[N],cy[N];

int opt[N];
int main(){
    read(n);
    rep(i,1,n){
        read(r[i].xl),read(r[i].xr),read(r[i].yl),read(r[i].yr);
        cx[2*i-1]=r[i].xl,cx[2*i]=r[i].xr;
        cy[2*i-1]=r[i].yl,cy[2*i]=r[i].yr;
    } 
    limx=limy=2*n;
    sort(cx+1,cx+2*n+1);sort(cy+1,cy+2*n+1);
    rep(i,1,n){
        r[i].xl=lower_bound(cx+1,cx+limx+1,r[i].xl)-cx;
        r[i].xr=lower_bound(cx+1,cx+limx+1,r[i].xr)-cx;
        r[i].yl=lower_bound(cy+1,cy+limy+1,r[i].yl)-cy;
        r[i].yr=lower_bound(cy+1,cy+limy+1,r[i].yr)-cy;
    }
    rep(i,1,n) opt[r[i].xl]=i,opt[r[i].xr]=-i;
    seg::build(1,limy);
    LL res3=0;
    rep(x,1,limx){
        int i=opt[x];
        if(i<0){
            i=-i;
            xryl.upd(r[i].yl,1);
            xryr.upd(r[i].yr,1);
            nwyl.upd(r[i].yl,-1);
            nwyr.upd(r[i].yr,-1);
            seg::upda(1,1,limy,r[i].yl,-1);
            seg::updb(1,1,limy,r[i].yr,-1);
            r[i].du+=xlyl.ask(r[i].yr)-xlyr.ask(r[i].yl-1)-1;
        }else{
            xlyl.upd(r[i].yl,1);
            xlyr.upd(r[i].yr,1);
            r[i].du-=xryl.ask(r[i].yr)-xryr.ask(r[i].yl-1);
            res3+=c2(nwyl.ask(r[i].yr)-nwyr.ask(r[i].yl-1))-seg::ask(1,1,limy,r[i].yl,r[i].yr).c;
            nwyl.upd(r[i].yl,1);
            nwyr.upd(r[i].yr,1);
            seg::upda(1,1,limy,r[i].yl,1);
            seg::updb(1,1,limy,r[i].yr,1);
        }
    }
    LL all=c3(n),res12=0;
    rep(i,1,n) res12+=1ll*(n-2)*r[i].du-2*c2(r[i].du);
    res12/=2;
    printf("%lld\n",all-res12-res3);
    return 0;
}
posted @ 2024-11-19 16:27  Cindy_Li  阅读(33)  评论(0)    收藏  举报