1. 程式人生 > >決心 - 行列式 - 貪心 - 可並堆

決心 - 行列式 - 貪心 - 可並堆

題目大意:一個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
            
           

相關推薦

決心 - 行列式 - 貪心 -

題目大意:一個n*n個矩陣,以及n個矩形 x 1 ,

[BZOJ2809][Apio2012]dispatching 貪心+

數據結構 pre amp apio2012 sizeof geo typedef 基本原理 要求 題目鏈接:http://www.lydsy.com/JudgeOnline/problem.php?id=2809 我們考慮以每一個節點作為管理者所得的最優答案,一定是優先選

【模板】左偏樹(

inline 限制 需要 表示 開始 cnblogs -a 刪除 ont 題目描述 如題,一開始有N個小根堆,每個堆包含且僅包含一個數。接下來需要支持兩種操作: 操作1: 1 x y 將第x個數和第y個數所在的小根堆合並(若第x或第y個數已經被刪除或第x和第y個數在

【bzoj2333】[SCOI2011]棘手的操作 +STL-set

space efi ras 當前 ati blog log down ace 題目描述 有N個節點,標號從1到N,這N個節點一開始相互不連通。第i個節點的初始權值為a[i],接下來有如下一些操作: U x y: 加一條邊,連接第x個節點和第y個節點 A1 x v: 將

BZOJ2809 [Apio2012]dispatching

style 操作 isp eap 超過 add 傳送門 int 什麽 歡迎訪問~原文出處——博客園-zhouzhendong 去博客園看該題解 題目傳送門 - BZOJ2809 題意概括   n個點組成一棵樹,每個點都有一個領導力和費用,可以讓一個點當領導,然後在這個

P3377 【模板】左偏樹(

return 表示 style 三次 限制 continue n) sta print P3377 【模板】左偏樹(可並堆) 題目描述 如題,一開始有N個小根堆,每個堆包含且僅包含一個數。接下來需要支持兩種操作: 操作1: 1 x y 將第x個數和第

試水--BZOJ1367: [Baltic2004]sequence

efi ide print sequence 否則 lose tar href -i n<=1e6個數,把他們修改成遞增序列需把每個數增加或減少的總量最小是多少? 方法一:可以證明最後修改的每個數一定是原序列中的數!於是$n^2$DP(逃) 方法二:把$A_i$改成$

真--模板--BZOJ2333: [SCOI2011]棘手的操作

def 操作 aps left getchar() 。。 每次 全局 log n<=300000個點,開始是獨立的,m<=300000個操作: 方法一:單點修改、查詢,區間修改、查詢?等等等等這裏修改是塊修改不是連續的啊,那就讓他連續唄!具體方法:離線後,每次

BZOJ 2333 SCOI2011 棘手的操作 查集+

swap 否則 cst can 使用 ++ 一個 多少 nio 。。題意概述就不寫了,各位老爺如果是看著玩的可以去搜一下,如果是做題找來的也知道題幹的。實際上是題幹無法縮減懶得復制ORZ 首先處理一下集合的合並和單點值查詢的問題。使用並查集,對於每個點記錄標記d表示這個點的

BZOJ3252: 攻略

merge 可並堆 網上 -- 每一個 tdi printf swa main 網上有很多人說用dfs序+線段樹做...其實stl的堆可以...可並堆可以...很多奇奇怪怪的東西都能做... 可並堆比較好想...也比較好寫... 分析: 首先,這是一個網絡流做不了的題

luogu3377 【模板】左偏樹(

merge ret || str AS pri https i++ 左偏樹 ref #include <iostream> #include <cstdio> using namespace std; int n, m, a[100005], opt

線段樹合並 define http har nod namespace 復雜度 scan The 可並堆 可並堆,又稱為左偏樹,滿足從一個節點一直向左兒子走比一直向右兒子走距離更長。 這樣,它就滿足了log層,也就是每次合並的時間復雜度為O(log) 合並:將一個合並

利用持久化優化實現K短路

fff bre style 距離 end 直接 所有 利用 lse 本來A*就可以搞定的題,為了怕以後卡復雜度,找了個這麽個方法 現階段水平不夠就不補充算法分析部分了 對於圖G,建立一個以終點t為起點的最短路徑構成的最短路徑樹 (就是反著跑一遍最短路,然後對於一個不為終點

左偏樹(

pow 們的 include lse fin \n def 兩個 printf “左偏”樹? 左偏樹其實是一種可並堆,它可以 \(O(log_2 n)\) 合並兩個堆。 那左偏?也就是說他左邊肯定有什麽東西比右邊大…… 別著急,在左偏樹上有一個叫距離的東西: 個點的距離,被

Luogu2483 [SDOI2010]魔法豬學院()

俞鼎力大牛的課件 對於原圖以 \(t\) 為根建出任意一棵最短路徑樹 \(T\),即反著從 \(t\) 跑出到所有點的最短路 \(dis\) 它有一些性質: 性質1: 對於一條 \(s\) 到 \(t\) 的路徑的邊集 \(P\),去掉 \(P\) 中和 \(T\) 的交集,記為 \(P'\)。 那

羅馬遊戲[]

傳送門 寫一個大根堆就可以了 , 注意並查集找fa不能路徑壓縮 , 因為每個點所在的集合的根是變化的 #include<bits/stdc++.h> #define N 1000050 using namespace std; struct Node{int l,r;}t[N

[APIO2012]派遣 []

傳送門 首先想到列舉每個點作為領導 , 然後我們需要快速查出x為根的子樹可以有多少個節點 滿足這些節點加起來不超過m 於是我們從下到上合併 , 維護一個小根堆(大的在上) , 如果堆的和>m就彈出堆頂 #include<bits/stdc++.h> #defin

luogu 3377【模板】左偏樹(

模板題嘛……就沒啥好講的了,如果不會左偏樹請看這篇blog 程式碼,上: #include<bits/stdc++.h> #define N 200005 using namespace std; int fa[N], ch[N][2], key[N],

[DP 維護凸包優化] BZOJ 4585 [Apio2016]煙火表演

垂死夢中驚坐起,膜拜神犇王夢迪 #include<cstdio> #include<cstdlib> #include<algorithm> using

總結

左偏樹 int mer(int x,int y){ if(x==0||y==0) return x+y; if(lt[x].val>lt[y].val) swap(x,y); rc=mer(rc,y); if(lt[lc].dis<lt[rc].dis) swap