Codeforces 1787C 思维,dp

该问题是一个涉及数组元素分解的优化问题,要求在一定的约束条件下找到每个元素的两个非负整数分解,使得特定函数F的值最小。解决方案利用动态规划,通过考虑每个元素分解对F的影响,确定最优的分解策略。动态规划状态dp[i][j]表示前i个元素中,第i个元素按j种方式分解时F的最小值。通过遍历所有可能的分解情况,最后得到F的最小值。
摘要由CSDN通过智能技术生成

题意:

给出一个有 n n n个元素的数组 a a a和一个常数 s s s,将每个元素 a i a_{i} ai分解为两个数 x i , y i x_{i},y_{i} xi,yi,满足
x i + y i = a i x i ≥ 0 y i ≥ 0 ( x i − s ) ⋅ ( y i − 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=aixi0yi0(xis)(yis)0
F F F
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=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+....+yn2xn1+yn1an
求出 F F F的最小值

Solution:

如果按顺序地考虑 a i a_{i} ai的分解情况,对 i ∈ [ 3 , n − 1 ] i\in[3,n-1] i[3,n1]的分解情况只会影响到 y i − 1 x i + y i x i + 1 y_{i-1}x_{i}+y_{i}x_{i+1} yi1xi+yixi+1这两项,同时有
y i = a i − x i y_{i}=a_{i}-x_{i} yi=aixi
则影响到的项为
y i − 1 x i + ( a i − x i ) x i + 1 y_{i-1}x_{i}+(a_{i}-x_{i})x_{i+1} yi1xi+(aixi)xi+1
除了下标为 i i i的项都是常数,那么这就是一个关于 x i x_{i} xi的一次函数,只会在 x i x_{i} xi的可能取值范围端点处取得最值

按题意, x i x_{i} xi的取值范围为下列两个不等式组的并集
{ x i ≤ s y i = a i − x i ≤ s x i ≥ 0 y i = a i − x i ≥ 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} xisyi=aixisxi0yi=aixi0

{ x i ≥ s y i = a i − x i ≥ s x i ≥ 0 y i = a i − x i ≥ 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} xisyi=aixisxi0yi=aixi0

这两个不等式组的解集为
[ m a x ( 0 , m i n ( s , a [ i ] − s ) ) , m i n ( a [ i ] , m a x ( 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))]
接下来只需要 d p dp dp取最大最小值的情况即可,设 d p [ i ] [ 0 / 1 ] dp[i][0/1] dp[i][0/1]为将 a i a_{i} ai分解为 x i x_{i} xi最小或最大的情况下前 i i i项的最小取值

i = 2 i=2 i=2
d p [ 2 ] [ 0 ] = a [ 1 ] ⋅ x [ 2 ] [ 0 ] d p [ 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 − 1 3\leq i \leq n-1 3in1时,枚举当前计算的状态 j j j,和从 i − 1 i-1 i1转移来的状态 k k k,有
d p [ i ] [ j ] = m i n ( d p [ i ] [ j ] , d p [ 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[i1][k]+y[i1][k]x[i][j])
F F F a n a_{n} an的分配无关,答案就为
m i n ( d p [ n − 1 ] [ 0 ] + y [ n − 1 ] [ 0 ] ⋅ a [ n ] , d p [ 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[n1][0]+y[n1][0]a[n],dp[n1][1]+y[n1][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;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值