做法:先來分析一下題目。從題目中的樣例,我們可以得到乙個猜想:後面的決策一定包含前面的決策。這個結論是可以證明的,證明過程這裡就不贅述了。因此,我們只需要分階段一步步在決策中新增住戶即可。對於某乙個決策,我們設離入口最遠的住戶編號是x,編號為i的住戶離入口的距離是s[i],新增的疲勞值是a[i],則要新增住戶無非就是兩種情況:一是在最遠住戶之前找乙個住戶新增入決策中,這樣新累積的疲勞值是a[i];二是在最遠住戶之後找乙個住戶新增入決策中,這樣新累積的疲勞值是a[i]+s[i]*2-s[x]*2。對於這兩種情況分別找出新增的疲勞值的最大值,然後再進行選擇即可。可是,用直接的方法找最大值是o(n)的,這樣使得整個程式是o(n^2),又因為n可達100000,因此這個方案不可行。此時我們就可以採用優先佇列來處理,將找最大值的複雜度減小到o(logn)。用兩個優先佇列q1,q2分別表示最遠住戶前面的住戶所新增的疲勞值組成的佇列和最遠使用者後面的住戶所新增的疲勞值組成的佇列,其中要注意的是,q1中第i住戶所對應的元素是a[i],而在q2中第i住戶所對應的元素是a[i]+s[i]*2。然後,對於每次決策,分別取q1和q2的頂端元素,比較q1的頂元素和q2的頂元素-s[x]*2(相當於比較a[i]和a[j]+s[j]*2-s[x]*2,即兩個住戶所新新增的疲勞值),如果選擇最遠住戶前面的住戶,則將答案累加後直接pop即可,如果選擇最遠住戶後面的住戶,就要注意將x後移,並將新的已成為最遠住戶前面住戶的元素加入q1中。在操作過程中,我們用乙個v陣列標記該住戶是否被選過,以便在提取最大值的時候不出現重複。
以下是本人**:
#include #include #include #include #include #include using namespace std;
int n,s[100010],a[100010];
bool v[100010]=;
typedef pairpa;
priority_queueq1,q2;
int main()
else
{ v[q2.top().second]=1;
ans+=t2;
while(x
NOIP2015普及組複賽T4 推銷員
阿明是一名推銷員,他奉命到螺絲街推銷他們公司的產品。螺絲街是一條死胡同,出口與入口是同乙個,街道的一側是圍牆,另一側是住戶。螺絲街一共有n nn家住戶,第i家住戶到入口的距離為s is i si 公尺。由於同一棟房子裡可以有多家住戶,所以可能有多家住戶與入口的距離相等。阿明會從入口進入,依次向螺絲街...
NOIP2015普及組複賽A 推銷員
略方法就是把疲勞值從小到大排個序,然後從尾部開始乙個乙個取,當選到第i i 2 個時有2種取法 一是取,那麼x i的答案就是 n i 1,n 區間的疲勞值求和並加上其中最大距離的2倍 二是不取,那麼答案便是 n i 2,n 區間的疲勞值求和並加上 1,n i 區間中 疲勞值 距離的2倍 最大的乙個,...
普及 NOIP 2015 推銷員 貪心
noip 2015 推銷員 題意 思路 貪心,首先按每戶人家的推銷疲勞度從大到小排序,考慮選定一組,走路帶來的疲勞度是定的,就是最遠那個 2.所以對於每個答案 max sum i mx 2 sum i 1 h i 其中sum是排序後對推銷疲勞度做的字首和,而h i 儲存 從 i 到 n中,最大的 2...