CSP2019 劃分 解題報告

2022-04-07 10:22:37 字數 1841 閱讀 3369

[csp2019] 劃分

有 \(n\) 個非負整數 \(a_i\)

\(( n \le 4 * 10^7)\), 將它們分為若干部分, 記為 \(s_i\), 要求 \(s_ \ge s_i\),

設 \(res=\sum_^ s_i^2\).

求 \(res\) 的最小值

考場上寫的做法.

設 \(f[i][j]\) 為第一段的起點為 \(i\), 終點為 \(j\) 時 \(res\) 的最小值.

樸素做法直接列舉 \(i,j,k\), 將 \(f[i][j]\) 從 \(f[j][k]\) 轉移過來.

優化:考慮中間的轉移點 \(j\), 對於每個 \(i, 合法的 \(k\) 的範圍是遞增的, 所以可以只列舉 \(i,j\) 然後指標 \(k\) 根據 \(sum_j-sum_\) 不斷忘前移, 並取最小值更新即可.

設總共有 \(k\) 個塊, 可以得出兩個性質.

性質 1: \(k\) 越大, 方案越優.

感性理解 : \(a^2+b^2 \le (a+b)^2\).

進一步推斷出,

性質 2: \(s_k\) 越小, 方案越優.

感性理解 : \(s_k\) 越小, 為了使得方案合法, 就強迫前面的 \(s\) 也要盡量地小, 由於 \(a\) 是非負整數, 所以 \(s\) 的值越小, \(k\) 就越大, 根據性質 1, 方案就越優.

這樣的話我們就可以維護乙個單調佇列, 對於每一位, 找到以它為結束點時, 最小的 \(s_k\).

在把新元素加入單調佇列時還有一些細節, 詳見**.

上面的做法加個高精 (高精這種東西早就忘光了好嗎...)

#include#define ll long long

using namespace std;

const int n=5e3+7;

const ll inf=5e18;

int n,ty;

ll a[n],sum[n],f[n][n],ans=inf;

void read()

ll p2(ll x)

int main()

memset(f,127,sizeof(f));

for(int i=1;i<=n;i++) f[i][n]=p2(sum[n]-sum[i-1]);

for(int j=n;j>=1;j--)

f[i][j]=min(f[i][j],minx+p2(sum[j]-sum[i-1]));

}} for(int i=1;i<=n;i++) ans=min(ans,f[1][i]);

printf("%lld\n",ans);

return 0;

}

#include#define ll long long

using namespace std;

const int n=4e7+7;

int n,ty,pre[n],que[n],t1,t2;

ll a[n],sum[n],lst[n],ans;

void read(){};

ll p2(ll x)

int main()

t1=t2=1;

que[1]=0;

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

int p=n;

while(p)

// for(int i=1;i<=n;i++) printf("pre[%d]: %d\n",i,pre[i]);

printf("%lld\n",ans);

return 0;

}

CSP2019 劃分 解題報告

csp2019 劃分 有乙個長度為 n 的序列 a i n le 4 times 10 7 求 sum a i 2 sum a i 2 dots sum 1 a i 2 的最小值.結論 上述式子能取到最小值,當且僅當最後一塊 即 sum 1 a i 取到了最小值.證明 暫時不會.那我們就 dp 保證...

CSP2019 樹的重心 解題報告

csp2019 樹的重心 t 組資料 1 le t le 5 每次給定一棵 n 個點的樹 1 le n le 299995 設 e 為樹的邊集,v x,v y 分別為刪去邊 x,y 後 點 x 所在的點集和點 y 所在的點集.求 sum left sum x 是 v x 的重心 x sum y 是 ...

CSP2019 JX 散步 解題報告

csp2019 jx 散步 有乙個長度為 l 的環 2 le l le 10 9 環上有 n 個人,m 個出口 1 le n,m le 2 times 10 5 規定第乙個出口的位置為 0 並將 到第乙個出口的距離 定義為 從順時針方向走到第乙個路口所走的路程 每個人有兩個屬性 t i,x i 分別...