Codeforces 1787C 思维,dp

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

题意:

给出一个有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=aixi0yi0(xis)(yis)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+....+yn2xn1+yn1an
求出FFF的最小值

Solution:

如果按顺序地考虑aia_{i}ai的分解情况,对i∈[3,n−1]i\in[3,n-1]i[3,n1]的分解情况只会影响到yi−1xi+yixi+1y_{i-1}x_{i}+y_{i}x_{i+1}yi1xi+yixi+1这两项,同时有
yi=ai−xi y_{i}=a_{i}-x_{i} yi=aixi
则影响到的项为
yi−1xi+(ai−xi)xi+1 y_{i-1}x_{i}+(a_{i}-x_{i})x_{i+1} yi1xi+(aixi)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} xisyi=aixisxi0yi=aixi0

{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} xisyi=aixisxi0yi=aixi0

这两个不等式组的解集为
[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-13in1时,枚举当前计算的状态jjj,和从i−1i-1i1转移来的状态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[i1][k]+y[i1][k]x[i][j])
FFFana_{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[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;
}

### Codeforces Round 1002 Div. 2 概述 Codeforces Round 1002 Div. 2 是一场面向较低评级选手的比赛,通常包含五道不同难度级别的编程挑战题。这类比赛旨在测试参赛者的算法思维能力和编码技巧。 对于该轮的具体题目及其解答方案,在当前提供的参考资料中并未直接提及此编号的比赛详情[^1]。然而,基于以往相似赛事的经验以及平台的一贯风格,下面给出一般性的描述和可能涉及的解法思路: #### A - Example Problem Title 假设A题是一个较为简单的入门级问题,它可能会考察基础的数据结构应用或是简单逻辑推理能力。解决方案往往依赖于清晰理解题目背景并运用基本循环控制语句实现目标功能。 ```cpp #include <iostream> using namespace std; void solve() { // 假设输入处理部分 int input; cin >> input; // 解决核心业务逻辑 if (input condition) { cout << "Expected Output"; } } ``` #### B - Another Simple Task B题则会稍微增加一点复杂度,比如引入数组操作或者是字符串匹配等内容。此时需要注意边界条件检查,并合理利用STL库函数简化代码编写过程。 ```cpp // 示例伪代码片段 vector<int> numbers; for (auto& num : numbers) { process(num); } if (!numbers.empty()) { do_something_with(numbers.back()); } ``` #### C - Intermediate Level Challenge 进入C级别之后,题目将会更加注重算法设计方面的要求,像贪心策略、动态规划等概念会被频繁使用到。这里的关键在于找到最优子结构性质来构建递推关系式求解最终答案。 ```cpp dp[0][0] = initial_value; for (size_t i = 1; i <= N; ++i) { dp[i][j] = min(dp[i-1][j], cost_of_transition + dp[i-1][prev_state]); } cout << result_based_on_dp_table; ``` #### D/E - Advanced Problems 最后两道高阶难题往往会涉及到图论模型建立、树形DP变换或者其他高级数据结构的应用场景分析。解决这些问题不仅考验个人技术功底更需要丰富的实战经验积累才能顺利攻克难关。 由于缺乏针对Codeforces Round 1002 Div. 2 的具体资料支持,上述内容仅作为参考模板展示如何按照惯例去构思各个层次的任务特点与应对方法[^2]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值