題目大意:給出乙個n*m(n,m<=5000)的網格,每個網格有互不相同的權值,定義兩個格仔聯通當且僅當從其中的某個格仔只向下或向右走能到達另乙個格仔,求網格中字典序最大的反鏈。
題解:反鏈即不存在乙個被選中的格仔位於另乙個被選中的格仔的右下方,要求字典序最大即每次選可選的格仔中權值最大的乙個。關鍵在於如何快速找到可選的權值最大的格仔。
由於每次被標記不合法的格仔會是左上或右下的一整塊,每一行可選的格仔是連續的一段。所以可以對每一行建一棵笛卡爾樹,查詢最大值時比較每一行笛卡爾樹根的權值即可。笛卡爾樹也可以方便地實現前後區間段的刪除。
第一次寫笛卡爾樹,感覺比較神奇(*^▽^*),維護乙個單調棧可以 o(n) 把乙個序列提成笛卡爾樹,詳見**。
code
#include
#include
#include
#include
#include
using namespace std;
typedef long long ll;
inline int
read()
while (c<='9'&&c>='0')
return num*f;
}inline ll readl()
while (c<='9'&&c>='0')
return num*f;
}int n,m,k,top,ans[5005][2],sta[5005],fa[5005][5005],ch[5005][5005][2],rt[5005],l[5005],r[5005];
ll p0,p1,q0,q1,a,b,c,d,a1,b1,c1,d1;
double a[5005][5005];
int main()
}for (int i=1;i<=k;i++)
for (int i=1;i<=n;i++) //對每一行建笛卡爾樹
if (top) ch[i][sta[top]][1]=j,fa[i][j]=sta[top];
sta[++top]=j;
}rt[i]=sta[1]; l[i]=1; r[i]=m;
}top=0;
while (1)
l[i]=rt[now]+1;
}for (int i=now+1;i<=n;i++) if (rt[i]&&rt[now]<=r[i])
r[i]=rt[now]-1;
}rt[now]=0;
}printf("%d\n",top);
for (int i=1;i<=top;i++) printf("%d
%d\n",ans[i][0],ans[i][1]);
return
0;}
SDOI2013 隨機數生成器
題意 給定 a,b,p,x 1 forall i 1,x i ax b 求最小的 i 滿足 x i t 若無解則輸出 1。0 leq a,b,x 1 t題解 挺水的一道題,展開之後bsgs即可。但 a leq 1 的地方需要特判,還巨複雜,有高中數學題內味了。複雜度 o sqrt 套路 includ...
SDOI2013 隨機數生成器
最近小 w 準備讀一本新書,這本書一共有 p 頁,頁碼範圍為 0 sim p 1 小 w 很忙,所以每天只能讀一頁書。為了使事情有趣一些,他打算使用 noi2012 上學習的線性同餘法生成乙個序列,來決定每天具體讀哪一頁。我們用 x i 來表示通過這種方法生成出來的第 i 個數,也即小 w 第 i ...
隨機數生成器
標頭檔案 內容 rand,srand函式和rand max常量 rand max 在windows系統中為32767 在類unix系統中為2147483647 rand 函式返回乙個0 rand max的隨機整數 srand seed 函式 接受unsigned int 型別的引數seed,以see...