日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【bzoj4444】[Scoi2015]国旗计划 倍增

發布時間:2023/12/10 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【bzoj4444】[Scoi2015]国旗计划 倍增 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目描述

給出一個圈和若干段,問:對于所有的 $i$ ,選擇第 $i$ 段的情況下,最少需要選擇多少段(包括第 $i$ 段)能夠覆蓋整個圈?

輸入

第1行,包含2個正整數N,M,分別表示邊防戰士數量和邊防站數量。 隨后n行,每行包含2個正整數。其中第i行包含的兩個正整數Ci、Di分別表示i號邊防戰士常駐的兩個邊防站編號, Ci號邊防站沿順時針方向至Di號邊防站力他的奔襲區間。數據保證整個邊境線都是可被覆蓋的。

輸出

輸出數據僅1行,需要包含n個正整數。其中,第j個正整數表示j號邊防戰士必須參加的前提下至少需要 多少名邊防戰士才能順利地完成國旗計劃

樣例輸入

4 8
2 5
4 7
6 1
7 3

樣例輸出

3 3 4 3


題解

倍增

如果將選擇的區間按照右端點正方向順序考慮的話,那么如果選擇了某個區間,下一個區間的選擇一定是所有左端點小于等于該區間右端點中,右端點最靠后的那一個。

因此首先斷環成鏈,然后選擇區間 $[l,r]$ 后,下一個選擇就應該是左端點在 $[1,r]$ 范圍內,右端點最靠后的。

所以對于每一個區間 $[l,r]$ ,在 $l$ 位置上加入 $r$ ,然后求前綴最大值即可得到每個位置選上一個區間后最遠能夠覆蓋到哪。

我們要求的是覆蓋整個圈,因此可以考慮倍增算法,預處理出 $f[i][j]$ 表示從 $j$ 位置選擇 $2^i$ 段區間最遠能夠覆蓋到哪。那么上面的全椎最大值就是 $f[0][j]$ 。

根據遞推式 $f[i][j]=f[i-1][f[i-1][j]]$ 預處理出 $f$ 數組,然后倍增求解。從大到小枚舉 $i$ ,如果加入一段不能覆蓋整個圈則加入,否則不加入。最后加上2(本身+無限逼近后剩余的一段)即為答案。

注意一下區間跨越 $m$ 的處理 ,詳見代碼。

時間復雜度 $O(n\log n)$

#include <cstdio> #include <cstring> #include <algorithm> #define N 200010 #define pos(x) lower_bound(v + 1 , v + m + 1 , x) - v using namespace std; int a[N] , b[N] , v[N << 1] , f[20][N << 2]; int main() {int n , m = 0 , i , j , t , ans;scanf("%d%*d" , &n);for(i = 1 ; i <= n ; i ++ ) scanf("%d%d" , &a[i] , &b[i]) , v[++m] = a[i] , v[++m] = b[i];sort(v + 1 , v + m + 1);for(i = 1 ; i <= n ; i ++ ){a[i] = pos(a[i]) , b[i] = pos(b[i]);if(a[i] < b[i]){f[0][a[i]] = max(f[0][a[i]] , b[i]);f[0][a[i] + m] = max(f[0][a[i] + m] , b[i] + m);}else{f[0][1] = max(f[0][1] , b[i]);f[0][a[i]] = max(f[0][a[i]] , b[i] + m);f[0][a[i] + m] = max(f[0][a[i] + m] , m << 1);}}for(i = 1 ; i <= m << 1 ; i ++ ) f[0][i] = max(f[0][i] , f[0][i - 1]);for(t = 1 ; (1 << t) <= m << 1 ; t ++ )for(i = 1 ; i <= m << 1 ; i ++ )f[t][i] = f[t - 1][f[t - 1][i]];for(i = 1 ; i <= n ; i ++ ){ans = 0;if(a[i] < b[i]) a[i] += m;for(j = t - 1 ; ~j ; j -- )if(f[j][b[i]] < a[i])ans += (1 << j) , b[i] = f[j][b[i]];printf("%d" , ans + 2);if(i < n) printf(" ");}return 0; }

?

轉載于:https://www.cnblogs.com/GXZlegend/p/8029235.html

總結

以上是生活随笔為你收集整理的【bzoj4444】[Scoi2015]国旗计划 倍增的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。