思路:首先可以知道,我們把一堆石子均分可以使答案盡量小,因為n堆m次搬運,所以可以分解石子堆(m-n)次,所以首先考慮用乙個優先佇列把每堆石子的數量放進去,然後每次彈出乙個最大值,再把這個值均分後得到的兩個數再放回到優先佇列裡,最後用佇列裡的值去計算平方和。
乍一看很對,但是忽略了一種情況,那就是均分兩次得到三份的解可能沒有一次均分成三份的解優,比如,12用前面的方法分成,而用後面的方法則能變為,顯然後面的平方和更小。
於是,我就考慮先把原來的平方和算出來,然後把每一堆均分為1份,2份…(m-n)份,再把每多分一次對答案的減少至放在優先佇列裡,最後佇列中取前(m-n)個元素即可
這樣答案毫無疑問是對的,但是每修改一次都要計算所有石子堆多分一次的結果,複雜度就在o(q∗n2) o(q*n^2)o(q∗n2),提交會超時,於是考慮先計算一遍所有石子堆的情況,放在優先佇列裡,然後如果某個堆的石子數要發生變化,就先把之前這堆對佇列裡的貢獻值刪去,再加入新的貢獻值。
1 #include 2view codeusing
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 }
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 除了第一次進佇...