決心 - 行列式 - 貪心 - 可並堆
題目大意:一個n*n個矩陣,以及n個矩形
,然後每個矩形等概率隨機其內部一個點點權+1(一開始全是0),問最後行列式的期望。
。
題解:
(一開始以為是m個矩形然後就開始懵逼我連
都不會……)
因為有n個矩形所有隻有n個位置有值所以這n個位置必須是個排列答案才不是0(廢話但是沒這個就不會做啦)
先考慮 怎麼做,判定x和y是否是兩個排列再統計逆序對數量奇偶性即可(廢話)。
然後考慮
怎麼做,首先這個時候x必須是個排列(否則某一行沒法選byebye),然後任何一種情況出現的概率是相同的(都是
),因此問題轉化為,對一個每行是一段連續的1的矩陣求行列式。
這個怎麼做,其實很簡單,考慮樸素的
的行列式,從小到大列舉每一列,然後隨便選取在這一列上有值的某行a,然後剩下這一列上有值的行b要減去a這一行。
考慮現在有任意一行是一段連續的1這個性質,因此每一列都選擇這一列有值的行中右端點最小的,假設這個右端點是r,這樣剩餘的行減去這一行相當於是這些行的左端點變成了r+1。
上述部分隨便用個什麼可並堆或者線段樹合併之類的即可。
然後最終的問題:
反過來考慮,即給每個矩形分配一個行x和列y,使得(x,y)在矩形內,並且x和y分別是排列,然後(行列式絕對值顯然會是1)統計行列式正負即可。
然後發現這兩部分幾乎是獨立的:你可以先分配行的排列,然後分配列的排列,然後看滿足
的
的數量的奇偶性,然後
,因此可以完全分成兩部分統計。(所以其實就是
的做法然後寫兩遍乘起來啊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