题目大意:一个n*n个矩阵,以及n个矩形
x
1
,
x
2
,
y
1
,
y
2
x_1,x_2,y_1,y_2
x1,x2,y1,y2,然后每个矩形等概率随机其内部一个点点权+1(一开始全是0),问最后行列式的期望。
n
≤
1
0
5
n\le10^5
n≤105。
题解:
(一开始以为是m个矩形然后就开始懵逼我连
x
1
=
x
2
,
y
1
=
y
2
x_1=x_2,y_1=y_2
x1=x2,y1=y2都不会……)
因为有n个矩形所有只有n个位置有值所以这n个位置必须是个排列答案才不是0(废话但是没这个就不会做啦)
先考虑 x 1 = x 2 , y 1 = y 2 x_1=x_2,y_1=y_2 x1=x2,y1=y2怎么做,判定x和y是否是两个排列再统计逆序对数量奇偶性即可(废话)。
然后考虑
x
1
=
x
2
x_1=x_2
x1=x2怎么做,首先这个时候x必须是个排列(否则某一行没法选byebye),然后任何一种情况出现的概率是相同的(都是
1
∏
i
=
1
n
Δ
y
i
\frac{1}{\prod_{i=1}^n\Delta y_i}
∏i=1nΔyi1),因此问题转化为,对一个每行是一段连续的1的矩阵求行列式。
这个怎么做,其实很简单,考虑朴素的
O
(
n
3
)
O(n^3)
O(n3)的行列式,从小到大枚举每一列,然后随便选取在这一列上有值的某行a,然后剩下这一列上有值的行b要减去a这一行。
考虑现在有任意一行是一段连续的1这个性质,因此每一列都选择这一列有值的行中右端点最小的,假设这个右端点是r,这样剩余的行减去这一行相当于是这些行的左端点变成了r+1。
上述部分随便用个什么可并堆或者线段树合并之类的即可。
然后最终的问题:
反过来考虑,即给每个矩形分配一个行x和列y,使得(x,y)在矩形内,并且x和y分别是排列,然后(行列式绝对值显然会是1)统计行列式正负即可。
然后发现这两部分几乎是独立的:你可以先分配行的排列,然后分配列的排列,然后看满足
x
i
<
x
j
,
y
i
>
y
j
x_i<x_j,y_i>y_j
xi<xj,yi>yj的
(
i
,
j
)
(i,j)
(i,j)的数量的奇偶性,然后
[
x
i
<
x
j
a
n
d
y
i
>
y
j
]
=
[
i
<
j
a
n
d
y
i
>
y
j
]
x
o
r
[
i
>
j
a
n
d
x
i
<
x
j
]
[x_i<x_j\ \mathrm{and}\ y_i>y_j]=[i<j\ \mathrm{and}\ y_i>y_j]\ \mathrm{xor}\ [i>j\ \mathrm{and}\ x_i<x_j]
[xi<xj and yi>yj]=[i<j and yi>yj] xor [i>j and xi<xj],因此可以完全分成两部分统计。(所以其实就是
x
1
=
x
2
x_1=x_2
x1=x2的做法然后写两遍乘起来啊QwQ)
#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define mod 1000000007
#define ull unsigned lint
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
namespace INPUT_SPACE{
const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;
char gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
inline int inn()
{
int x,ch;while((ch=gc())<'0'||ch>'9');
x=ch^'0';while((ch=gc())>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
}using INPUT_SPACE::inn;
inline int fast_pow(int x,int k,int ans=1) { for(;k;k>>=1,x=(lint)x*x%mod) (k&1)?ans=(lint)ans*x%mod:0;return ans; }
const int N=100003;
namespace QwQ{
int id[N],p[N],node_cnt,val[N],lef[N],rig[N],dis[N];
inline int new_node(int v,int d)
{
int x=++node_cnt;dis[x]=0;
val[x]=v,p[id[x]=d]=x;
return lef[x]=rig[x]=0,x;
}
int merge_lst(int x,int y)
{
if(!x||!y) return x+y;
if(val[x]>val[y]) swap(x,y);
rig[x]=merge_lst(rig[x],y);
if(dis[rig[x]]>dis[lef[x]]) swap(lef[x],rig[x]);
if(rig[x]) dis[x]=dis[rig[x]]+1;else dis[x]=0;
return x;
}
struct lst{
int rt;
inline int init() { return rt=0; }
inline int merge(const lst &t) { return rt=merge_lst(rt,t.rt); }
inline int pop() { return rt=merge_lst(lef[rt],rig[rt]); }
inline int topv() { return val[rt]; }
inline int topid() { return id[rt]; }
inline int empty() { return !rt; }
inline int insert(int v,int id) { return rt=merge_lst(rt,new_node(v,id)); }
}t[N];
inline int solve(pii *ps,int n)
{
node_cnt=0;rep(i,1,n) t[i].init();int ans=1,xs=1,l,r,v,d;
rep(i,1,n) t[l=ps[i].fir].insert(r=ps[i].sec,i),xs=xs*(r-l+1ll)%mod;
rep(i,1,n)
{
while(!t[i].empty()&&t[i].topv()<i) t[i].pop();
if(t[i].empty()) return 0;
v=t[i].topv(),d=t[i].topid(),t[i].pop();
if(v<n) t[v+1].merge(t[i]);
if(d^i) ans*=-1,p[id[p[i]]=d]=p[i];
}
if(ans<0) ans+=mod;
return (lint)ans*fast_pow(xs,mod-2)%mod;
}
}using QwQ::solve;
pii p1[N],p2[N];
int main()
{
for(int T=inn(),n;T;T--)
{
n=inn();
rep(i,1,n) p1[i].fir=inn(),p1[i].sec=inn(),p2[i].fir=inn(),p2[i].sec=inn();
printf("%lld\n",(lint)solve(p1,n)*solve(p2,n)%mod);
}
return 0;
}