题意:
给出一个有nnn个元素的数组aaa和一个常数sss,将每个元素aia_{i}ai分解为两个数xi,yix_{i},y_{i}xi,yi,满足
xi+yi=aixi≥0yi≥0(xi−s)⋅(yi−s)≥0
x_{i}+y_{i}=a_{i}\\
x_{i}\geq 0 \\
y_{i}\geq 0 \\
(x_{i}-s)\cdot(y_{i}-s)\geq 0
xi+yi=aixi≥0yi≥0(xi−s)⋅(yi−s)≥0
记FFF为
F=a1x2+y2x3+y3x4+....+yn−2xn−1+yn−1an
F=a_{1}x_{2}+y_{2}x_{3}+y_{3}x_{4}+....+y_{n-2}x_{n-1}+y_{n-1}a_{n}
F=a1x2+y2x3+y3x4+....+yn−2xn−1+yn−1an
求出FFF的最小值
Solution:
如果按顺序地考虑aia_{i}ai的分解情况,对i∈[3,n−1]i\in[3,n-1]i∈[3,n−1]的分解情况只会影响到yi−1xi+yixi+1y_{i-1}x_{i}+y_{i}x_{i+1}yi−1xi+yixi+1这两项,同时有
yi=ai−xi
y_{i}=a_{i}-x_{i}
yi=ai−xi
则影响到的项为
yi−1xi+(ai−xi)xi+1
y_{i-1}x_{i}+(a_{i}-x_{i})x_{i+1}
yi−1xi+(ai−xi)xi+1
除了下标为iii的项都是常数,那么这就是一个关于xix_{i}xi的一次函数,只会在xix_{i}xi的可能取值范围端点处取得最值
按题意,xix_{i}xi的取值范围为下列两个不等式组的并集
{xi≤syi=ai−xi≤sxi≥0yi=ai−xi≥0
\begin{cases}
x_{i}\leq s \\
y_{i}=a_{i}-x_{i}\leq s \\
x_{i}\geq 0 \\
y_{i}=a_{i}-x_{i} \geq 0
\end{cases}
⎩⎨⎧xi≤syi=ai−xi≤sxi≥0yi=ai−xi≥0
{xi≥syi=ai−xi≥sxi≥0yi=ai−xi≥0 \begin{cases} x_{i}\geq s \\ y_{i}=a_{i}-x_{i}\geq s \\ x_{i}\geq 0 \\ y_{i}=a_{i}-x_{i} \geq 0 \end{cases} ⎩⎨⎧xi≥syi=ai−xi≥sxi≥0yi=ai−xi≥0
这两个不等式组的解集为
[max(0,min(s,a[i]−s)),min(a[i],max(s,a[i]−s))]
[max(0,min(s,a[i]-s)),min(a[i],max(s,a[i]-s))]
[max(0,min(s,a[i]−s)),min(a[i],max(s,a[i]−s))]
接下来只需要dpdpdp取最大最小值的情况即可,设dp[i][0/1]dp[i][0/1]dp[i][0/1]为将aia_{i}ai分解为xix_{i}xi最小或最大的情况下前iii项的最小取值
当i=2i=2i=2时
dp[2][0]=a[1]⋅x[2][0]dp[2][1]=a[1]⋅x[2][1]
dp[2][0]=a[1]\cdot x[2][0]\\
dp[2][1]=a[1]\cdot x[2][1]\\
dp[2][0]=a[1]⋅x[2][0]dp[2][1]=a[1]⋅x[2][1]
当3≤i≤n−13\leq i \leq n-13≤i≤n−1时,枚举当前计算的状态jjj,和从i−1i-1i−1转移来的状态kkk,有
dp[i][j]=min(dp[i][j],dp[i−1][k]+y[i−1][k]⋅x[i][j])
dp[i][j]=min(dp[i][j],dp[i-1][k]+y[i-1][k]\cdot x[i][j]) \\
dp[i][j]=min(dp[i][j],dp[i−1][k]+y[i−1][k]⋅x[i][j])
FFF与ana_{n}an的分配无关,答案就为
min(dp[n−1][0]+y[n−1][0]⋅a[n],dp[n−1][1]+y[n−1][1]⋅a[n])
min(dp[n-1][0]+y[n-1][0]\cdot a[n],dp[n-1][1]+y[n-1][1]\cdot a[n])
min(dp[n−1][0]+y[n−1][0]⋅a[n],dp[n−1][1]+y[n−1][1]⋅a[n])
//#include<bits/stdc++.h>
#include<iostream>
#include<cstdio>
#include<bitset>
#include<cstdlib>
#include<cassert>
#include<cstring>
#include<cmath>
#include<utility>
#include<vector>
#include<cctype>
#include<utility>
#include<stack>
#include<queue>
#include<unordered_map>
#include<unordered_set>
#include<string>
#include<ctime>
#include<algorithm>
#include<map>
#include<set>
using namespace std;
using ll=long long;
const int N=2e5+5,inf=0x3fffffff;
const ll INF=0x3fffffffffffffff,mod=1e9+7;
ll dp[N][2],x[N][2],y[N][2],last[N][2];
int n,s,a[N];
inline void work() {
cin>>n>>s;
/**
* x[i]+y[i]=a[i]
* (x[i]-s)*(y[i]-s)>=0
* F=a[1]*x[2]+(y[2]*x[3]+y[3]*x[4]+...+y[n-2]*x[n-1])+y[n-1]*a[n];
*/
for(int i=1;i<=n;i++) {
cin>>a[i];
x[i][0]=max(0,min(s,a[i]-s));
x[i][1]=min(a[i],max(s,a[i]-s));
for(int j=0;j<=1;j++) {
y[i][j]=a[i]-x[i][j];
dp[i][j]=INF;
}
}
dp[2][0]=a[1]*x[2][0];
dp[2][1]=a[1]*x[2][1];
for(int i=3;i<n;i++) {
for(int j=0;j<=1;j++) {
for(int k=0;k<=1;k++) {
dp[i][j]=min(dp[i][j],dp[i-1][k]+y[i-1][k]*x[i][j]);
}
}
}
cout<<min(dp[n-1][0]+y[n-1][0]*a[n],dp[n-1][1]+y[n-1][1]*a[n])<<endl;
}
int main() {
#ifdef stdjudge
freopen("in.txt","r",stdin);
#endif
cin.tie(nullptr);
ios::sync_with_stdio(false);
int t; cin>>t;
while(t--) work();
#ifdef stdjudge
freopen("CON","r",stdin);
std::cout<<std::flush;
system("pause");
#endif
return 0;
}
该问题是一个涉及数组元素分解的优化问题,要求在一定的约束条件下找到每个元素的两个非负整数分解,使得特定函数F的值最小。解决方案利用动态规划,通过考虑每个元素分解对F的影响,确定最优的分解策略。动态规划状态dp[i][j]表示前i个元素中,第i个元素按j种方式分解时F的最小值。通过遍历所有可能的分解情况,最后得到F的最小值。
1296

被折叠的 条评论
为什么被折叠?



