首页 > 其他分享 >【题解】P4027 [NOI2007] 货币兑换

【题解】P4027 [NOI2007] 货币兑换

时间:2023-01-06 20:55:37浏览次数:44  
标签:P4027 int 题解 top NOI2007 rate maxn cdq cases

题意好长,但是不想概括了。

\cdq/!

思路

cdq 分治 + 凸包。

首先考虑令 \(f_i\) 表示第 \(i\) 天可以得到的最大金额,\(f_1 = s\)

因为 \(rate_i\) 是常数,并且保证存在最优方案使得每次买进卖出都是全部金额,所以最优方案下第 \(i\) 天的 A 券和 B 券的比例是固定的,令第 \(i\) 天的 A 券有 \(x_i\) 个,B 券有 \(y_i\) 个

可以列方程组:

\[\begin{cases} \frac{x_i}{y_i} = rate_i \\ x_i A_i + y_i B_i = f_i \end{cases} \]

解得

\[\begin{cases} x_i = \frac{f_i \cdot rate_i}{a_i + rate_i b_i} \\ y_i = \frac{f_i}{a_i + rate_i b_i} \end{cases} \]

第 \(i\) 天卖出它们可以得到的金额是 \(x_i A_i + y_i B_i\),把 \(B_i\) 提出来:

\(B_i (\frac{A_i}{B_i} x_i + y_i)\)

括号里面是一个一次函数的形式,\(x_i\) 是斜率,\(y_i\) 是截距。

所以现在的问题变成了:

  1. 插入一条直线

  2. 求最高点

好家伙,没啥单调的东西,有人整了用 splay 维护的 \(O(n \log n)\) 好活,但我看不懂。

于是考虑用 cdq 分治进行动态转静态。

静态的情况下可以直接把所有转移点按照斜率排序构造凸包。

查询前先按 \(x\) 排序,又是可以指针维护的东西。

注意到转移对下标的前后顺序也有要求,这里可以先在 cdq 处理当前层的时候分拣出下标在中点两侧的元素,最后再归并起来,复杂度就优化了。

时间复杂度 \(O(n \log n)\),wonderful!

代码

#include <cstdio>
#include <algorithm>
using namespace std;

const int maxn = 1e5 + 5;

struct line
{
    double k, b, x;
} s[maxn], q[maxn], l;

struct item
{
    int p;
    double x;
} c[maxn], sr[maxn];

double interx(line& a, line& b) { return (a.k == b.k ? (a.b < b.b ? 1e12 : -1e12) : (b.b - a.b) / (a.k - b.k));}

int n, top;
double a[maxn], b[maxn], rate[maxn], f[maxn];

void solve(int l, int r)
{
    if (l == r)
    {
        f[l] = max(f[l], f[l - 1]);
        s[l].b = f[l] / (b[l] + rate[l] * a[l]);
        s[l].k = s[l].b * rate[l];
        return;
    }
    int mid = (l + r) >> 1, tl = l - 1, tr = 0;
    for (int i = l; i <= r; i++)
        if (c[i].p <= mid) c[++tl] = c[i];
        else sr[++tr] = c[i];
    for (int i = mid + 1; i <= r; i++) c[i] = sr[i - mid];
    solve(l, mid);
    top = 0;
    for (int i = l; i <= mid; i++)
    {
        while ((top > 1) && interx(s[i], q[top]) < q[top].x) top--;
        q[++top] = s[i];
        q[top].x = interx(s[i], q[top - 1]);
    }
    for (int i = mid + 1, p = 1; i <= r; i++)
    {
        while ((p < top) && (q[p + 1].x < c[i].x)) p++;
        int pos = c[i].p;
        f[pos] = max(f[pos], a[pos] * q[p].k + b[pos] * q[p].b);
    }
    solve(mid + 1, r);
    tr = mid + 1;
    top = 0;
    for (int i = l; i <= mid; i++)
    {
        while ((tr <= r) && (s[tr].k < s[i].k)) q[++top] = s[tr++];
        q[++top] = s[i];
    }
    while (tr <= r) q[++top] = s[tr++];
    for (int i = l; i <= r; i++) s[i] = q[i - l + 1];
}

bool cmp(const item& a, const item& b) { return (a.x < b.x); }

int main()
{
    // freopen("P4027_1.in", "r", stdin);
    scanf("%d%lf", &n, &f[1]);
    for (int i = 1; i <= n; i++)
    {
        scanf("%lf%lf%lf", &a[i], &b[i], &rate[i]);
        c[i] = (item){i, a[i] / b[i]};
    }
    sort(c + 1, c + n + 1, cmp);
    solve(1, n);
    printf("%.3lf\n", f[n]);
    return 0;
}

标签:P4027,int,题解,top,NOI2007,rate,maxn,cdq,cases
From: https://www.cnblogs.com/lingspace/p/p4027.html

相关文章

  • 【题解】CF1178G The Awesomest Vertex
    题意给定一棵大小为\(n\)的树以及\(m\)个操作,定义一个结点\(u\)的权值为:\(|\sum\limits_{w\inR(v)}a_w|\cdot|\sum\limits_{w\inR(v)}b_w|\)其中\(R(v)......
  • 230102模拟题解
    t1容易发现对于奇数和偶数,能满足条件的长度分别是单调的,所以可以分别二分答案检查。检查的时候对于差分序列做哈希即可,然后用set/map/哈希表判\(B\)的子段是否有\(A......
  • CF865B Ordering Pizza 题解
    简要题意:有\(n\)个人去披萨店吃披萨,有两种披萨,每个披萨有\(m\)片。现在第\(i\)个人要吃\(c_i\)片披萨,如果吃一片第一种披萨会获得\(a_i\)的幸运值,如果吃一片第二......
  • configmap出现/n问题解决
    1.现象原始文件肉眼显示正常,如下图命令行显示整个data部分成了一坨,回车全变成了/n,虽然不影响使用,但是对维护查看比较麻烦,如下图2.问题原因1.配置文件里有一些Tab......
  • [CTSC2009]魔幻花园 题解
    [CTSC2009]魔幻花园题解洛谷链接。一、问题转化原问题等价于求某个水平面上所有点围成凸包的面积的最小值。首先考虑把三维问题转化到二维上:考虑到任意时刻所有点都在......
  • I. 西行妖下题解
    题目内容原题链接样例输入5201样例输出?44232?35155?52431!32154题解首先,题目有一个很难解决的痛点,就是他只会返回最前面的那......
  • Codeforces Round #842 (Div. 2) A-D题解
    比赛链接A、GreatestConvex非常的简单。根据样例直接猜是输出\(n-1\).上一个\(Python\)代码。T=int(input())whileT>0:T-=1n=int(input())......
  • USACO Au题解
    T1一眼背包,但是很怪考虑设dp[i][j][k]表示前i个物品还剩j个月饼还剩k个冰激凌。$O(n^4)$显然。转移O(n)枚举用钱还是优惠券。瓶颈在于冰激凌的优惠。考虑如何把这一......
  • idea 内存参数修改不生效问题解决 VM参数设置不生效解决
    提示:在idea的工具栏Help->EditCustomVMOptions内修改 对应参数-Xmx1024m后重启无效的再看下面的方法 问题:ieda的默认内存大小是1024M当我开多个工......
  • PIP 更新后不能使用的使用 提示: No module named 'pip'问题解决
    1、问题引入   正确安装Python以后,Python和PIP都可以正常使用。在使用pip安装其他库的时候,提示PIP版本过低,建议更新,结果更新时发生错误,导致PIP不能被识别,具体如下图......