测试

题目链接

$ \text{Solution} $


首先拆开最初那个小式子:

\[f(\{x_n\}) = \sum_{i=1}^{n} \sum_{j=i+1}^{n} (x_i+x_j)^2 \]

\[= \frac{1}{2}(\sum_{i=1}^{n}\sum_{j=1}^{n}(x_i+x_j)^2-4\sum_{i=1}^{n}x_i^2) \]

\[= \frac{1}{2}(\sum_{i=1}^{n}\sum_{j=1}^{n}(x_i^2+x_j^2+2x_ix_j)-4\sum_{i=1}^{n}x_i^2) \]

\[=\frac{1}{2}(\sum_{i=1}^n(nx_i^2+\sum_{j=1}^{n}x_j^2+2x_i\sum_{j=1}^{n}x_j)-4\sum_{i=1}^nx_i^2) \]

\[=\frac{1}{2}(n\sum_{i=1}^{n}x_i^2+n\sum_{i=1}^{n}x_i^2+2(\sum_{i=1}^{n}x_i)^2-4\sum_{i=1}^{n}x_i^2) \]

\[= (n-2)(\sum_{i=1}^{n}x_i^2) + (\sum_{i=1}^{n}x_i)^2 \]

然后看看两行合并起来的式子:

\[f(\{x_n\})+f(\{y_n\}) \]

\[= (n-2)(\sum_{i=1}^n(x_i^2+y_i^2))+(\sum_{i=1}^{n}x_i)^2+(\sum_{i=1}^{n}y_i)^2 \]

\[= (n-2)(\sum_{i=1}^{n}x_i^2+y_i^2) + \]

\[(\sum_{i=1}^{n}x_i^2+2\sum_{i=1}^nx_i\sum_{j=1}^{i-1}x_j) +(\sum_{i=1}^ny_i^2+2\sum_{i=1}^ny_i\sum_{j=1}^{i-1}y_j) \]

\[=(n-1)(\sum_{i=1}^{n}(x_i^2+y_i^2)) + 2(\sum_{i=1}^nx_i\sum_{j=1}^{i-1}x_j+\sum_{i=1}^ny_i\sum_{j=1}^{i-1}y_j) \]

操作:决定是否交换一些位置上的 \(x_i\),\(y_i\).

注意到无论怎么操作,前面这半个式子的值都是一定的,那么我们只需要使后面这个式子最小就可以了。

由于每个位置交换或不交换可以看作 \(1\) 和 \(0\),且每个操作对结果造成的影响比较小,容易想到动态规划这些小的影响从而得到最优解。注意到式子里有个前缀和,且这个前缀和的值域很小, \(10^4\) 级别。所以考虑设一维跟前缀和有关的 \(\operatorname{dp}\).

开始 \(\operatorname{dp}\)!

  1. 发现前缀和不太好从之前状态确定,所以采用刷表法。

  2. 注意到 $ {\forall k \in [1,n], \sum_{i=1}^k x_i+y_i } $ 为定值,所以如果确定了操作完前 \(k\) 个位置后的 \(\sum_{i=1}^kx_i\),我们就可以 \(O(1)\) 得到此时的 \(\sum_{i=1}^ky_i\)。

  3. 设 \(\operatorname{dp_{k,S}}\) 表示当前考虑到第 \(k\) 个位置,操作后 \(s = \sum_{i=1}^kx_i\) 时 \(\sum_{i=1}^kx_i\sum_{j=1}^{i-1}x_j + \sum_{i=1}^ky_i\sum_{j=1}^{i-1}y_j\) 的值。

  4. 对于每个位置都有两个方程,分别对应交换或者不交换的情况。

  5. 边界条件 \(\operatorname{dp}_{0,0}=0\),其他的位置初始都为正无穷。

可以写出以下方程:

若在这一位不交换,

\[\operatorname{dp}_{k,s+x_k} = \min\{\operatorname{dp}_{k-1,s} + s\times x_k +(\sum_{i=1}^{k-1}(x_i+y_i)-s)*y_k \} \]

若在这一位交换,直接把上面式子的 \(x_k\) 和 \(y_k\) 换过来即可,

\[\operatorname{dp}_{k,s+y_k} = \min\{ \operatorname{dp}_{k-1,s} + s\times y_k + (\sum_{i=1}^{k-1}(x_i+y_i)-s)*x_k \} \]

最后,枚举前缀和 \(s\),答案就是最小的 \(\operatorname{dp}_{n,s}\) 乘以 \(2\) 加上一开始左半边的式子。

关于复杂度:

  1. 注意到 \(\sum_{i=1}^{k-1}(x_i+y_i)\) 可以在扫描过程中顺便 \(O(1)\) 处理出来,所以不用算进复杂度里。

  2. 注意到一开始左半边那个式子可以对于每组数据 \(O(n)\) 预处理出来。

  3. 设 \(v\) 为前缀和值域,则最后的时间复杂度为 \(O(\sum n \times \sum v)\)

实现细节:

  1. 注意两行前缀和爆出 \(10000\) 的情况,因为是两行,所以最大的前缀和可能会是 \(20000\) 这个量级的,但是爆的情况肯定不优,可以特判掉也可以直接数组开大一点。

点击查看缺省源"Jairon.h"

#include <bits/stdc++.h>
using namespace std;

#define lint long long

#include <"Jairon.h">

#define maxn 1000010
#define SIZE 5010

int n,ans=0;
int a[maxn];
int b[maxn];
int pre[maxn];
int dp[110][20010];

int main(){
	int T=read(_);
	while(T--){
		ans=0; read(n);
		FOR(i,1,n){ read(a[i]); }
		FOR(i,1,n){ read(b[i]); }
		if(n==1){ puts("0"); continue; }
		FOR(i,1,n){ ans+=sqr(a[i])+sqr(b[i]); }
		FOR(i,1,n){ pre[i]=pre[i-1]+a[i]+b[i]; }
		ans*=(n-1); int Mn=inf,res=0;
		FOR(i,1,n){ memset(dp[i],0x3f,sizeof dp[i]); }

		dp[0][0]=0;
		FOR(i,1,n){
			FOR(j,0,pre[i-1]){
				chmin(dp[i][j+a[i]],dp[i-1][j]+(j)*a[i]+(pre[i-1]-j)*b[i]);
				chmin(dp[i][j+b[i]],dp[i-1][j]+(j)*b[i]+(pre[i-1]-j)*a[i]);
			}
		}

		FOR(j,0,pre[n]){ if(dp[n][j]==inf){ continue; } chmin(Mn,ans+2*dp[n][j]); }
		outn(Mn);
	}
	return 0;
}

/**/
posted @ 2026-02-15 01:11  Jair271  阅读(23)  评论(0)    收藏  举报