[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 分別...