E 石子搬運 優先佇列 思維

2022-06-02 03:54:11 字數 1589 閱讀 9919

思路:首先可以知道,我們把一堆石子均分可以使答案盡量小,因為n堆m次搬運,所以可以分解石子堆(m-n)次,所以首先考慮用乙個優先佇列把每堆石子的數量放進去,然後每次彈出乙個最大值,再把這個值均分後得到的兩個數再放回到優先佇列裡,最後用佇列裡的值去計算平方和。

乍一看很對,但是忽略了一種情況,那就是均分兩次得到三份的解可能沒有一次均分成三份的解優,比如,12用前面的方法分成,而用後面的方法則能變為,顯然後面的平方和更小。

於是,我就考慮先把原來的平方和算出來,然後把每一堆均分為1份,2份…(m-n)份,再把每多分一次對答案的減少至放在優先佇列裡,最後佇列中取前(m-n)個元素即可

這樣答案毫無疑問是對的,但是每修改一次都要計算所有石子堆多分一次的結果,複雜度就在o(q∗n2) o(q*n^2)o(q∗n2),提交會超時,於是考慮先計算一遍所有石子堆的情況,放在優先佇列裡,然後如果某個堆的石子數要發生變化,就先把之前這堆對佇列裡的貢獻值刪去,再加入新的貢獻值。

1 #include 2

using

namespace

std;

3 typedef long

long

ll;4

#define mst(a,b) memset((a),(b),sizeof(a))

5#define rush() int t;scanf("%d",&t);while(t--)

6const

int maxn=405;7

const

int inf=0x3f3f3f3f;8

const ll mod=998244353;9

10int

n,m;

11ll a[maxn];

12ll add[maxn];

13 mapint>mp;

1415

intmain()

1623

intt;

24 scanf("

%d",&t);

25 priority_queue,less>q;

26for(int i=1;i<=n;i++)36}

37int sz=0;38

int cc=(m-n)*2;39

while

(q.size())

43while(t--)

5859

for(int i=0;i//

刪除之前的貢獻

6064

65 a[id]=v;

66 sum+=v*v;

6768 pre=a[id]*a[id];

69for(int i=1;i<=m-n;i++) //

加上現在的貢獻

7077

78 ll ans=sum;

79 sz=0;80

for(int i=1;i<=m-n;i++)

86while

(q.size())

91 printf("

%lld\n

",ans);92}

93return0;

94 }

view code

Function (思維 優先佇列)

解題思路 因為 x 是正整數,所以每個 fi 都必須先分配 xi 1。這時候還剩下 m n 個 1 沒有分配,採用貪心原則。首先需要先知道對於每一次分配的1,產生的增量為 所以我們每次都取最小的增量,最後即為最小的增量。這就用到了優先佇列 ac code 1 include 2 include 3 ...

codeforces 731E 優先佇列 DP

題意 給出n個數字,a和b兩個人依次選中1 k k 2 把他們合併之後自己分數加上這些數的和。求兩個人在最右策略下a最多領先b多少。當數字只剩下乙個之後遊戲馬上結束。用 dp i 0 1 表示前i個數字被合併,現在是a b先手到最後遊戲結束最多領先多少。故a要最大化後繼狀態的值,b要最小化後繼狀態的...

2018CCPC網路賽A(優先佇列,思維)

include using namespace std priority queue q int main q.push 賣出 tmp x q.top first 如果前面沒有比它更小的,相當於放進去乙個標記為1的 如果有比它更小的,相當於執行買賣 if q.top second 1 除了第一次進佇...