SCOI2015 國旗計畫

2022-03-26 22:01:08 字數 1059 閱讀 8099

題目

首先考慮一下環形的區間覆蓋問題怎麼做

我們可以把環倍長成鏈,之後驚訝的發現我只會列舉乙個\(i\)作為起點跑\([i,i+m]\)的區間覆蓋

看起來非常垃圾,但是會這樣做就夠了

考慮列舉到的這個\(i\)作為乙個某乙個給定的區間的左端點的時候,想要覆蓋\([i,i+m]\)這段區間這個給定的區間是必須選擇的,於是我們對於每乙個給定的區間\([l_i,r_i]\),來算一下覆蓋\([l_i,l_i+m]\)的最少要用多少個區間即可

這是乙個非常經典的貪心,我們把區間按照左端點排序,貪心地選擇左端點不超過當前區間右端點中右端點最大的即可

題目中保證了任意兩個區間不相互包含,也就是說我們按照左端排序之後右端點也是單調的,我們只需要利用單調性就可以求出每個區間的最優轉移了

對於乙個區間\([l_i,r_i]\),我們順著最優轉移走,直到當前區間的右端點不小於\(l_i+m\),那麼\([l_i,l_i+m]\)就被完全覆蓋了,答案就是中間經過的區間個數

考慮讓每個區間向其最優轉移連邊,這樣我們就得到了一棵樹,我們只需要在樹上倍增一下就能快速計算了

**

#include#define re register

inline int read()

const int maxn=4e5+5;

struct ee[maxn];

struct sega[maxn];

int n,m,sz,t;

int head[maxn],num,id[maxn],lg[maxn];

int f[20][maxn],deep[maxn];

inline void add(int x,int y)

inline int cmp(const seg &a,const seg &b)

for(re int j=lg[deep[x]];j>=0;--j)

if(f[j][x]&&a[f[j][x]].rprintf("%d ",deep[id[i]]-deep[f[0][x]]+1);

} return 0;

}

SCOI2015 國旗計畫

演算法難度5,思維難度6,難度5 給定乙個長度為m mm的環,環上有m mm個點 1,m 1,m 1,m 以及n nn個互不包含的區間。要求對於每個區間求出,在必須選這個區間的前提下,能使得所有被選區間覆蓋整個環的最少區間數。1 n 2 1 05,m 10 91 le n le 2 times 10...

SCOI2015 國旗計畫

斷環為鏈,將環複製兩倍。用to i j 表示從點i出發,走 2 j 步能夠到達的最遠的 右端點qwq 的編號。注意為了方便判斷已經走了一圈了,我們最後一步先不要跳,只需要判斷當前右端點仍在i n之前即可。然後這個樣子的話,最後答案需要 1。如下 include include include inc...

SCOI2015 國旗計畫

bzoj luogu 先考慮破環為鏈 由於區間不包含,我們sort之後可以貪心的選左端點在當前右端點之前的最後乙個 然後預處理乙個倍增陣列,每次logn查一下 複雜度 o nlogn 空間兩倍,tot 1的r設為inf includeusing namespace std const int 4e5...