Sol.CF1637D
闲话
昨天打 CGR-19 的时候,就像大本钟上送外卖——上面寄,下面摆,第二道题卡死以后就彻底摆了,放飞自我(已经结束了 Nanoda!),和男足被别人进一个球就士气崩溃的精神差不多。
然后,掉大分!!!
正题
本题难度:蓝(提高+ / 省选-)。
标签:数学,DP。
直接上数学推导过程:
原式:
\(\sum_{i=1}^{n}\sum_{j=i+1}^{n}(a_i+a_j)^2\)
展开:
\(=\sum_{i=1}^{n}\sum_{j=i+1}^{n}(a_i^2+2a_ia_j+a_j^2)\)
分离 \(a_i\) 与 \(a_j\)。
\(=\sum_{i=1}^{n}[a_i^2(n-i)+2a_i\sum_{j=i+1}^{n}a_j+\sum_{j=i+1}^{n}a_j^2]\)
因为关于 \(b\) 的式子和关于 \(a\) 的式子同理,所以把它们直接相加并且化简,就是答案要求的式子:
\(=\sum_{i=1}^{n}[(a_i^2+b_i^2)(n-i)+2a_i\sum_{j=i+1}^{n}a_j+2b_i\sum_{j=i+1}^{n}b_j+\sum_{j=i+1}^{n}(a_j^2+b_j^2)]\)
对于原来的两个数组,我们可以发现一些显然的性质:
-
\(\sum_{j=i+1}^{n}(a_i^2+b_i^2)\) 为定值。
-
\(\sum_{j=i+1}^{n}a_j+\sum_{j=i+1}^{n}b_j\) 为定值。
发现具体的求解过程中,当前结果与前面结果的联系仅在于后缀和,所以我们可以设计一个 DP 过程,来求解这个式子的最小值。
因为 \(1 \leq a_i,b_i \leq 100\) ,所以 \(\sum_{j=i+1}^{n}a_j \leq 10000\)。
设 \(s=\sum_{j=i}^{n}a_j\) ,
可以用 \(dp_i,s\) 来表示当前位置 \(i\) ,后缀和为 \(s\) 时,结果的最小值。
从 \(n\) 到 \(1\),每次扫遍所有可能的后缀和,枚举交换和不交换进行计算转移即可,详细过程见以下代码。
for(int i=n-1;i>=1;i--){
//cul dp[i][j];
for(int j=0;j<=10000;j++){//枚举后缀和
dp[i][j+a[i]]=min(dp[i][j+a[i]],dp[i+1][j]+(a[i]*a[i]+b[i]*b[i])*(n-i)+2ll*a[i]*j+2ll*b[i]*(ts[i+1]-j)+tpfs[i+1]);
dp[i][j+b[i]]=min(dp[i][j+b[i]],dp[i+1][j]+(a[i]*a[i]+b[i]*b[i])*(n-i)+2ll*b[i]*j+2ll*a[i]*(ts[i+1]-j)+tpfs[i+1]);
}
}
注意多组数据要清空。
完整代码:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int T;
int n;
ll a[110];
ll b[110];
ll ts[110],tpfs[110];
//hzh und pf-uzh
ll dp[110][10110];
int main(){
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cin>>T;
while(T--){
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
}
memset(ts,0,sizeof(ts));
memset(tpfs,0,sizeof(tpfs));
for(int i=n;i>=1;i--){
ts[i]=ts[i+1]+a[i]+b[i];
tpfs[i]=tpfs[i+1]+a[i]*a[i]+b[i]*b[i];
}
memset(dp,0x3f,sizeof(dp));
dp[n][a[n]]=dp[n][b[n]]=0;
for(int i=n-1;i>=1;i--){
//cul dp[i][j];
for(int j=0;j<=10000;j++){
dp[i][j+a[i]]=min(dp[i][j+a[i]],dp[i+1][j]+(a[i]*a[i]+b[i]*b[i])*(n-i)+2ll*a[i]*j+2ll*b[i]*(ts[i+1]-j)+tpfs[i+1]);
dp[i][j+b[i]]=min(dp[i][j+b[i]],dp[i+1][j]+(a[i]*a[i]+b[i]*b[i])*(n-i)+2ll*b[i]*j+2ll*a[i]*(ts[i+1]-j)+tpfs[i+1]);
}
}
ll ans=LLONG_MAX;
for(int i=0;i<=10000;i++){
ans=min(ans,dp[1][i]);
}
cout<<ans<<endl;
}
return 0;
}