【题解】P1412 经营与开发(DP)

Description

给出 \(n\) 个星球,每个星球有一个类型,如果该星球 \(i\) 类型是 \(1\) 则我们可以在它上面挖钻,可以得到 \(a[i] \times p\) 的价值(p是我们的钻头的属性),每次用完之后属性会变成 \(p \times (1-0.01 \times k\)。 如果类型是 \(2\),我们可以在上面修理钻头,花费 \(b[i]*p\) 的价格可以让我们的钻头属性变成 \(p \times (1+0.01 \times c)\)。输出最大可以获得的价值。可以透支价值(假装有信用卡)

Sample Input

5 50 50 10

1 10

1 20

2 10

2 20

1 30

Sample Output

375.00

Solution

我们发现这题如果我们从 \(1\) 推到 \(n\) 那么的话我们发现其实钻头的值会对后面的答案有影响。

那么怎么办?

我们可以考虑一个可以计算出钻头属性的状态。

灵光一动: \(f[i][j][k]\) 表示前 \(i\) 个,选了 \(j\) 个星球挖矿, \(k\) 个星球修钻头可以获得的最大价值。

那么转移就很简单了,同时我们还可以用滚动数组优化空间。(虽然优化了还是过不了。。。)

时间复杂度 \(O(N^3)\)

空间复杂度 \(O(N^2)\)

贴个代码:

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

int w,k,c;
const int N=1005,INF=1E9;
int type[N],a[N],sum[N];
double f[2][N][N];

inline double power(double a,int b){
    double ret=1.0;
    while(b){
        if(b&1) ret*=a;
        a*=a;
        b>>=1;
    }
    return ret;
}

int main(){
    int n=0;
    scanf("%d%d%d%d",&n,&k,&c,&w);
    for(int i=1;i<=n;++i)
        scanf("%d%d",&type[i],&a[i]),sum[i]=sum[i-1]+(type[i]&1);
    memset(f,-60,sizeof(f));
    f[0][0][0]=0;
    double ans=-INF;
    double p1=1-0.01*(double)k,p2=1+0.01*(double)c;
    for(int i=1;i<=n;++i){
        int now=i%2,pre=(i-1)%2;
        memset(f[now],-60,sizeof(f[now]));
        for(int j=0;j<=sum[i];++j)
            for(int k=0;k<=i-sum[i];++k){
                f[now][j][k]=f[pre][j][k];
                if(type[i]==1 && j>=1)
                    f[now][j][k]=max(f[now][j][k],f[pre][j-1][k]+(double)a[i]*power(p1,j-1)*power(p2,k));
                if(type[i]==2 && k>=1)
                    f[now][j][k]=max(f[now][j][k],f[pre][j][k-1]-(double)a[i]*power(p1,j)*power(p2,k-1));
                ans=max(ans,f[now][j][k]);
            }
        }
    printf("%.2lf\n",ans*(double)w);
    return 0;
}

那么我们怎么快乐的A掉这道题捏?

我们来先写个式子:

我们设 \(k_i\) 是 \((1-0.01 \times k)\) 或者 \((1+0.01 \times c)\) 。

\(a[1]*w+a[2]*w*k_1+a[3]*w*k_1*k_2+a[4]*w*k_1*k_2*k_3...\)

那么我们先提出:

\(w*[a[1]+a[2]*k_1+a[3]*k_1*k_2+a[4]*k_1*k_2*k_3...]\)

那么我们可以直接用秦某韶的公式

\(w*[a[1]+k_1*(a[2]+k_2*(a[3]+a[4]*k_3...))]\)

那么我们发现:
!!!怎么越到最后值越固定,并且好像从里到外求值好像不具有后效性。

我们想到了一个绝妙的方法只可惜这里。。。

算了,我们发现可以直接从里到外求值并且只要保证里面的局部最优就可以了。

那么我们从后到前枚举并且保证有后面局部最优。

那么枚举一下就可以了。

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

int w,k,c;
double ans;
const int N=1e5+5,INF=1E9;
int type[N],a[N];

int main(){
    int n=0;
    scanf("%d%d%d%d",&n,&k,&c,&w);
    for(int i=1;i<=n;++i)
        scanf("%d%d",&type[i],&a[i]);
    ans=0.0;
    for(int i=n;i>=1;--i)
        if(type[i]==1) ans=max(ans,ans*(1.0-0.01*(double)k)+(double)a[i]);
        else ans=max(ans,ans*(1.0+0.01*(double)c)-(double)a[i]);
    printf("%.2lf\n",ans*(double)w);
    return 0;
}

原文地址:https://www.cnblogs.com/JCNL666/p/11079890.html

时间: 2024-08-27 10:51:49

【题解】P1412 经营与开发(DP)的相关文章

洛谷 P1412 经营与开发

P1412 经营与开发 题目描述 4X概念体系,是指在PC战略游戏中一种相当普及和成熟的系统概念,得名自4个同样以“EX”为开头的英语单词. eXplore(探索) eXpand(拓张与发展) eXploit(经营与开发) eXterminate(征服) ——维基百科 今次我们着重考虑exploit部分,并将其模型简化: 你驾驶着一台带有钻头(初始能力值w)的飞船,按既定路线依次飞过n个星球. 星球笼统的分为2类:资源型和维修型.(p为钻头当前能力值) 1.资源型:含矿物质量a[i],若选择开采

noip模拟赛 经营与开发

题目描述 4X概念体系,是指在PC战略游戏中一种相当普及和成熟的系统概念,得名自4个同样以"EX"为开头的英语单词. eXplore(探索) eXpand(拓张与发展) eXploit(经营与开发) eXterminate(征服) --维基百科 今次我们着重考虑exploit部分,并将其模型简化: 你驾驶着一台带有钻头(初始能力值w)的飞船,按既定路线依次飞过n个星球. 星球笼统的分为2类:资源型和维修型.(p为钻头当前能力值) 1.资源型:含矿物质量a[i],若选择开采,则得到a[i

经营与开发(noip2014 模拟题)

[题目描述] 4X概念体系,是指在PC战略游戏中一种相当普及和成熟的系统概念,得名自4个同样以“EX”为开头的英语单词. eXplore(探索) eXpand(拓张与发展) eXploit(经营与开发) eXterminate(征服) ——维基百科 今次我们着重考虑exploit部分,并将其模型简化: 你驾驶着一台带有钻头(初始能力值w)的飞船,按既定路线依次飞过n个星球. 星球笼统的分为2类:资源型和维修型.(p为钻头当前能力值) 1.资源型:含矿物质量a[i],若选择开采,则得到a[i]*p

【题解】SOFTWARE 二分+搜索/dp

题目描述 一个软件开发公司同时要开发两个软件,并且要同时交付给用户,现在公司为了尽快完成这一任务,将每个软件划分成m个模块,由公司里的技术人员分工完成,每个技术人员完成同一软件的不同模块的所用的天数是相同的,并且是已知的,但完成不同软件的一个模块的时间是不同的,每个技术人员在同一时刻只能做一个模块,一个模块只能由一个人独立完成而不能由多人协同完成.一个技术人员在整个开发期内完成一个模块以后可以接着做任一软件的任一模块.写一个程序,求出公司最早能在什么时候交付软件. 输入输出格式 输入格式: 输入

题解——P1133 教主的花园DP

直接设二维状态具有后效性,会爆零 然后需要加一维 然后70 看了题解之后发现没有考虑1和n的关系 考虑之后,四十 然后懵逼 突然发现自己的ans更新写错了,导致每次ans都是第一个取30的情况的解 然后回到70 之后修改了一下初始化 初始化的时候也要注意排除自己假设之外的情况 100 #include <cstdio> #include <algorithm> #include <cstring> using namespace std; int n,dp[200200

0x50 动态规划(0x5C 计数类DP)例题3:装饰围栏(题解)(计数类DP讲解,确定第k个排列)

计数类DP一般就是确定DP状态,DP出排名范围,然后不断逼近. 题意 题目链接 [题目描述] 有 N 块长方形的木板,长度分别为1,2,-,N,宽度都是1. 现在要用这 N 块木板组成一个宽度为 N 的围栏,满足在围栏中,每块木板两侧的木板要么都比它高,要么都比它低. 也就是说,围栏中的木板是高低交错的. 我们称"两侧比它低的木板"处于高位,"两侧比它高的木板"处于低位. 显然,有很多种构建围栏的方案. 每个方案可以写作一个长度为N的序列,序列中的各元素是木板的长度

HUAS 1477 经营与开发(贪心)

考虑DP,令dp[i][j][k]当前在第i个星球,用了j次维修,k次开采后所获得的最大价值.复杂度为O(n^3).超时 如果我们发现,对于初始时能力值为w所能产生的最大价值y,初始时能力值为1所能产生的最大价值x,显然会有y=w*x. 也就是说能力值的变化不会对单位能力值所能产生的最大价值发生变化的. 如果我们令f[i]表示从第i个星球以单位能力值出发所能产生的最大价值. 那么对于当前的星球所产生的选择,只会对第i+1的星球的能力值产生变化,所以考虑从后往前贪心的进行选择.即可. # incl

题解——[ZJOI2010]数字计数 数位DP

最近在写DP,今天把最近写的都放上来好了,,, 题意:给定两个正整数a和b,求在[a,b]中的所有整数中,每个数码(digit)各出现了多少次. 首先询问的是一个区间,显然是要分别求出1 ~ r ,1 ~ l的答案,然后相减得到最终答案 首先我们观察到,产生答案的区间是连续的,且可以被拆分, 也就是说0 ~ 987的贡献= 0 ~ 900 + 901 ~ 987的恭喜, 同理,把位拆开也是等价的,所以我们可以单独计算每个位的贡献 这样讲可能有点不太清晰,举个例子吧 3872 我们先把它按数拆开来

【题解】Luogu P3584 LAS dp

一个状态超多的dp 考虑对食物转移,设f[][0/1/2/3]表示不被选/被左吃/被右吃/被两边吃 只要考虑全每一种状态即可 dp void dp(int x,int y){ if(~f[x][2]&&a[x]>=a[y])f[y][0]=2; else if(~f[x][3]&&a[x]>=a[y]*2)f[y][0]=3; if(~f[x][0]&&a[x]<=a[y])f[y][1]=0; else if(~f[x][1]&&