决心 - 行列式 - 贪心 - 可并堆

题目大意:一个n*n个矩阵,以及n个矩形 x 1 , x 2 , y 1 , y 2 x_1,x_2,y_1,y_2 ,然后每个矩形等概率随机其内部一个点点权+1(一开始全是0),问最后行列式的期望。 n 1 0 5 n\le10^5
题解:
(一开始以为是m个矩形然后就开始懵逼我连 x 1 = x 2 , y 1 = y 2 x_1=x_2,y_1=y_2 都不会……)
因为有n个矩形所有只有n个位置有值所以这n个位置必须是个排列答案才不是0(废话但是没这个就不会做啦)

先考虑 x 1 = x 2 , y 1 = y 2 x_1=x_2,y_1=y_2 怎么做,判定x和y是否是两个排列再统计逆序对数量奇偶性即可(废话)。

然后考虑 x 1 = x 2 x_1=x_2 怎么做,首先这个时候x必须是个排列(否则某一行没法选byebye),然后任何一种情况出现的概率是相同的(都是 1 i = 1 n Δ y i \frac{1}{\prod_{i=1}^n\Delta y_i} ),因此问题转化为,对一个每行是一段连续的1的矩阵求行列式。
这个怎么做,其实很简单,考虑朴素的 O ( n 3 ) O(n^3) 的行列式,从小到大枚举每一列,然后随便选取在这一列上有值的某行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 ( 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] ,因此可以完全分成两部分统计。(所以其实就是 x 1 = x 2 x_1=x_2 的做法然后写两遍乘起来啊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;
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/84798926