P3592(区间dp)

果然又废又很久没有打题,打坐半天可以的,效率0
题目:click
题意:在这里插入图片描述

我们先来考虑题目。每个不同的区间,选择最小的且 < = C [ i ] <=C[i] <=C[i],显然贪心的话不能够去确定最大的消费值,由可能最小值设定的小来洗车的人多或者加个大。考虑从dp入手,n个洗车店的价格每一个可以可以选择一个接着后头的,由于涉及到区间,可以设定成dp[i][j]:表示从i-j区间最大的花钱总和,由于每个区间需要一个最小值来计算价值确定,设dp[i][j][k]:区间i-j包含的所有区间,i-j区间中最小值为k,花钱最大。可以建立转移方程:
d p [ i ] [ j ] [ k ] = m a x { d p [ i ] [ p o s − 1 ] [ x ] + d p [ p o s + 1 ] [ j ] [ y ] + n u m ∗ k } 。 x , y ≥ k dp[i][j][k]=max\{dp[i][pos-1][x]+dp[pos+1][j][y]+num*k\}。x,y\geq k dp[i][j][k]=max{dp[i][pos1][x]+dp[pos+1][j][y]+numk}x,yk,num表示包含完整区间经过pos的个数,他们就会选择第pos的洗车地方进行消费k元。由于x,y的位置不确定,可以把dp[i][j][k]定义为:区间i-j内最小值大于等于k的最大消费。通过pre[i][j][k]数组去确定大于等于k的最小值到底是多少,MAX[i][j][k]表示:最小值等于k的时候最大花费的位置是在i-j区间的哪个位置,逆推就可以转出转移路径输出答案。

#include<cmath>
#include<iostream>
#include<sstream>
#include<cstdio>
#include<cstring>
#include<string>
#include<cstdlib>
#include<istream>
#include<vector>
#include<stack>
#include<set>
//#include<unordered_map>
#include<map>
#include<algorithm>
#include<queue>
#define mmp make_pair
#define inf 0x3f3f3f3f
#define llinf 0x7fffffffffffffff
using namespace std;
typedef long long ll;
typedef pair<ll,ll> PP;
typedef double ld;
int gcd(int a,int b) {
    if(!b) return a;
    else return gcd(b,a%b);
}
struct A {
    int aa,bb,cc;
}a[4010];
int dp[55][55][4010],pre[55][55][4010];//pre记录最小的k值
int MAX[55][55][4010];// dp[i][j][x]//x>=k 的max的位置
int num[55][4010];//第i个洗车店 价格为j可以洗的数量
int ANS[55];
vector<ll>hh;
inline ll fiind(ll x) {
    ll temp=lower_bound(hh.begin(),hh.end(),x)-hh.begin();
    if(temp==hh.size())
        return -1;
    return temp+1;
}
void dfsans(int l,int r,int k) {
    if(l>r) return ;
    k=pre[l][r][k];
    int pos=MAX[l][r][k];
    ANS[pos]=hh[k-1];
    dfsans(l,pos-1,k);
    dfsans(pos+1,r,k);
}
int main() {
    ios::sync_with_stdio(false);
    int n,m;
    scanf("%d %d",&n,&m);
    for(int i=1;i<=m;++i) {
        scanf("%d %d %d",&a[i].aa,&a[i].bb,&a[i].cc);
        hh.push_back(a[i].cc);
    }
    sort(hh.begin(),hh.end());
    hh.erase(unique(hh.begin(),hh.end()),hh.end());
    for(int i=1;i<=m;++i) {
        a[i].cc=fiind(a[i].cc);
    }
    memset(dp,0,sizeof(dp));
    for(int i=n;i>0;--i) {
        for(int j=i;j<=n;++j) {
            for(int k=i;k<=j;++k) {
                for(int l=0;l<=hh.size()+2;++l)
                    num[k][l]=0;
            }
            for(int k=1;k<=m;++k) {
                if(i<=a[k].aa && j>=a[k].bb) {
                    for(int l=a[k].aa;l<=a[k].bb;++l)
                        ++num[l][a[k].cc];
                }
            }
            for(int k=i;k<=j;++k) {
                for(int l=hh.size();l>0;--l) {
                    num[k][l]+=num[k][l+1];
                }
            }
            for(int k=hh.size();k>0;--k) {
                int maxn=0;
                for(int pos=i;pos<=j;++pos) {
                    int w=dp[i][pos-1][k]+dp[pos+1][j][k]+num[pos][k]*hh[k-1];
                    if(maxn<=w) {
                        maxn=w; MAX[i][j][k]=pos;
                    }
                }
                if(maxn>=dp[i][j][k+1]) {
                    dp[i][j][k]=maxn;
                    pre[i][j][k]=k;
                }
                else {
                    dp[i][j][k]=dp[i][j][k+1];
                    pre[i][j][k]=pre[i][j][k+1];
                }
            }
        }
    }
    printf("%d\n",dp[1][n][1]);
    dfsans(1,n,1);
    for(int i=1;i<=n;++i)
        printf("%d ",ANS[i]);
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
为了用 MATLAB 复现上述方程,您需要先确定所需的参数和初始条件。其中,参数包括泵浦光和信号光的吸收截面、发射截面和增益系数,以及掺杂离子的浓度和光纤的损耗系数;初始条件包括泵浦光和信号光的初始功率和位置。 在确定好参数和初始条件之后,您可以使用 MATLAB 中的 ODE 求解器来求解该方程组。具体步骤如下: 1. 定义一个函数,用于计算方程组的右侧项。该函数应该接受两个变量,即位置和功率,然后返回方程组的右侧项。 2. 定义初始条件,包括泵浦光和信号光的初始功率和位置。 3. 调用 MATLAB 中的 ODE 求解器(如 ode45)来求解方程组。您需要将上述定义的函数和初始条件作为参数传递给求解器。 下面是一个示例代码,用于求解上述方程组: ``` % 定义参数 Gamma_p = 0.01; % 泵浦光增益系数 Gamma_s = 0.02; % 信号光增益系数 sigma_alpha_p = 1.2e-25; % 泵浦光吸收截面 sigma_e_p = 1.0e-25; % 泵浦光发射截面 sigma_alpha_s = 2.0e-25; % 信号光吸收截面 sigma_e_s = 1.8e-25; % 信号光发射截面 N_Yb = 1.0e26; % 铒离子浓度 N_Er = 8.0e25; % 镱离子浓度 delta_p = 0.001; % 泵浦光损耗系数 delta_s = 0.002; % 信号光损耗系数 % 定义初始条件 P_p0 = 1.0e-3; % 泵浦光初始功率 P_s0 = 1.0e-6; % 信号光初始功率 z0 = 0; % 初始位置 % 定义求解区间和步长 zspan = [0 10]; % 求解范围 h = 0.01; % 步长 % 定义方程组的右侧项 dp = @(z, P) -Gamma_p * (sigma_alpha_p * N_Yb - (sigma_alpha_p + sigma_e_p) * conj(N_Yb) * P(1)) * P(1) - delta_p * P(1); ds = @(z, P) -Gamma_s * (sigma_alpha_s * N_Er - (sigma_alpha_s + sigma_e_s) * conj(N_Er) * P(2)) * P(2) ... + Gamma_s * sigma_e_s * N_Er * P_p0 - delta_s * P(2); % 求解方程组 [z, P] = ode45(@(z, P) [dp(z, P); ds(z, P)], zspan, [P_p0; P_s0]); % 绘制泵浦光和信号光的功率随位置的变化 figure; plot(z, P(:, 1), 'r-', z, P(:, 2), 'b-'); xlabel('位置(m)'); ylabel('功率(W)'); legend('泵浦光', '信号光'); ``` 请注意,在这个示例代码中,我们假设泵浦光和信号光的初始位置都为零,求解范围为 $0$ 到 $10$,步长为 $0.01$。您可以根据实际情况修改这些值。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值