P1412 经营与开发

题目描述

4X概念体系,是指在PC战略游戏中一种相当普及和成熟的系统概念,得名自4个同样以“EX”为开头的英语单词。

eXplore(探索)

eXpand(拓张与发展)

eXploit(经营与开发)

eXterminate(征服)

——维基百科

今次我们着重考虑exploit部分,并将其模型简化:

你驾驶着一台带有钻头(初始能力值w)的飞船,按既定路线依次飞过n个星球。

星球笼统的分为2类:资源型和维修型。(p为钻头当前能力值)

1.资源型:含矿物质量a[i],若选择开采,则得到a[i]*p的金钱,之后钻头损耗k%,即p=p*(1-0.01k)

2.维修型:维护费用b[i],若选择维修,则支付b[i]*p的金钱,之后钻头修复c%,即p=p*(1+0.01c)

注:维修后钻头的能力值可以超过初始值(你可以认为是翻修+升级)

金钱可以透支。

请作为舰长的你仔细抉择以最大化收入。

输入输出格式

输入格式:

第一行4个整数n,k,c,w。

以下n行,每行2个整数type,x。

type为1则代表其为资源型星球,x为其矿物质含量a[i];

type为2则代表其为维修型星球,x为其维护费用b[i];

输出格式:

一个实数(保留2位小数),表示最大的收入。

输入输出样例

输入样例#1: 复制
5 50 50 10
1 10
1 20
2 10
2 20
1 30
输出样例#1: 复制
375.00

说明

【数据范围】

对于30%的数据 n<=100

另有20%的数据 n<=1000;k=100

对于100%的数据 n<=100000; 0<=k,c,w,a[i],b[i]<=100;保证答案不超过10^9

先上30分的代码(三维数组空间开不了那么大)

三维

f(i,j,k)代表前i个,开采j个,维护k个的最大价值

设p1,p2为那两个固定系数

t=1

f(i,j,k)=max(f(i-1,j,k),f(i-1,j-1,k)+p1^(j-1)*p2^k*a[i])

t=2

f(i,j,k)=max(f(i-1,j,k),f(i-1,j,k-1)+p1^j*p2^(k-1)*a[i])

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 2147483647
const ll INF = 0x3f3f3f3f3f3f3f3fll;
#define ri register int
template <class T> inline T min(T a, T b, T c)
{
    return min(min(a, b), c);
}
template <class T> inline T max(T a, T b, T c)
{
    return max(max(a, b), c);
}
template <class T> inline T min(T a, T b, T c, T d)
{
    return min(min(a, b), min(c, d));
}
template <class T> inline T max(T a, T b, T c, T d)
{
    return max(max(a, b), max(c, d));
}
#define pi acos(-1)
#define me(x, y) memset(x, y, sizeof(x));
#define For(i, a, b) for (int i = a; i <= b; i++)
#define FFor(i, a, b) for (int i = a; i >= b; i--)
#define mp make_pair
#define pb push_back
const int maxn = 100005;
#define mod 100003
const int N=200;

// name*******************************
double f[N][N][N];
double p1,p2;
int n;
double k,c,w;
int t[N];
double a[N],b[N];
double ans=0;
int s1[N];
int s2[N];
// function******************************
double qmul(double a,int b)
{
    double base=a;
    double ans=1;
    while(b)
    {
        if(b&1)
            ans*=base;
        base*=base;
        b>>=1;
    }
    return ans;
}

//***************************************
int main()
{
//    freopen("test.txt","r",stdin);
    cin>>n>>k>>c>>w;
    For(i,1,n)
    {
        s1[i]=s1[i-1];
        s2[i]=s2[i-1];
        cin>>t[i];
        if(t[i]==1)
        {
            cin>>a[i];
            s1[i]++;
        }
        else
        {
            cin>>b[i];
            s2[i]++;
        }
    }
    p1=1-0.01*k;
    p2=1+0.01*c;
    fill(&f[0][0][0],&f[N-1][N-1][N-1],-inf);

    f[0][0][0]=0;
    For(i,1,n)
    {
        For(j,0,s1[i])
        {
            For(k,0,s2[i])
            {
                f[i][j][k]=f[i-1][j][k];
                if(t[i]==1&&j>=1)
                    f[i][j][k]=max(f[i][j][k],f[i-1][j-1][k]+qmul(p1,j-1)*qmul(p2,k)*a[i]);
                if(t[i]==2&&k>=1)
                    f[i][j][k]=max(f[i][j][k],f[i-1][j][k-1]-qmul(p1,j)*qmul(p2,k-1)*b[i]);
                ans=max(ans,f[i][j][k]);
//                cout<<i<<","<<j<<","<<k<<":"<<f[i][j][k]<<endl;
            }
        }
    }
    printf("%.2f",ans*w);
    return 0;
}
View Code

再看一维神奇代码

逆着走,就能压成一维了!!!

记最终答案为ans,其实对于每个星球不管是维修还是资源型,都可以把对钻头的改变度记作一个常数k,而且k是有后效性的。

我们先具一个i=4的例子,

ans=w*k1*a1+w*k1*k2*a2+w*k1*k2*k3*a3+w*k1*k2*k3*k4*a4,

即ans=w*(k1*a1+k1*k2*a2+k1*k2*k3*a3+k1*k2*k3*a4),

进一步提公因式就是ans=w*(k1*(a[1]+k2*(a[2]+k3*(a[3]+k4*a[4]))))

所以我们发现从最里面往外面走是最好的,也就是逆着推,真特么神奇

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define inf 2147483647
const ll INF = 0x3f3f3f3f3f3f3f3fll;
#define ri register int
template <class T> inline T min(T a, T b, T c)
{
    return min(min(a, b), c);
}
template <class T> inline T max(T a, T b, T c)
{
    return max(max(a, b), c);
}
template <class T> inline T min(T a, T b, T c, T d)
{
    return min(min(a, b), min(c, d));
}
template <class T> inline T max(T a, T b, T c, T d)
{
    return max(max(a, b), max(c, d));
}
#define pi acos(-1)
#define me(x, y) memset(x, y, sizeof(x));
#define For(i, a, b) for (int i = a; i <= b; i++)
#define FFor(i, a, b) for (int i = a; i >= b; i--)
#define mp make_pair
#define pb push_back
const int maxn = 100005;
#define mod 100003
const int N=100005;

// name*******************************
int n;
double f[N];
double k,c,w;
int t[N];
double a[N],b[N];
double ans=-inf;
// function******************************


//***************************************
int main()
{
//    freopen("test.txt","r",stdin);

    scanf("%d%lf%lf%lf",&n,&k,&c,&w);
    For(i,1,n)
    {
        scanf("%d",&t[i]);
        if(t[i]==1)
            scanf("%lf",&a[i]);
        else
            scanf("%lf",&b[i]);
    }
    double p1=1-0.01*k;
    double p2=1+0.01*c;
    For(i,0,n)
    f[i]=-inf;
    f[n+1]=0;
    FFor(i,n,1)
    {
        if(t[i]==1)
            f[i]=max(f[i+1],f[i+1]*p1+a[i]);
        else
            f[i]=max(f[i+1],f[i+1]*p2-b[i]);
    }
    printf("%.2f",f[1]*w);

    return 0;
}
原文地址:https://www.cnblogs.com/planche/p/8659533.html