2020 ICPC沈阳站H题 The Boomsday Project

题目链接:点这里
首先,第一步要把每一次租车当作一次独立的事件提取出来,按照发生的时间进行从小到大排序,就转换为一个线性DP。
a [ i ] = p a[i] = p a[i]=p i i i 次租车的天数

f [ i ] = f [ i − 1 ] + r f[i] = f[i-1] + r f[i]=f[i1]+r 从上一次租车转移

考虑第 j j j 种办卡方式对答案的影响

f o r ( i , 1 − c n t ) / / for(i, 1-cnt)// for(i,1cnt)// i i i 次租车
f o r ( j , 1 − n ) / / for(j, 1-n)// for(j,1n)// j j j 种办卡方式

假设在处理第 i i i 次租车办第 j j j 种卡的影响下考虑第 j j j 种卡的天数和次数影响下从左往右的临界下标为 x x x ,即从 x − i − 1 x - i-1 xi1都可以通过买第 j j j 种卡转移到第 i i i 次租车,复杂度为 O ( c n t × ∑ j = 1 n m i n ( k j , d j ) × n ) O(cnt\times \displaystyle\sum^{n}_{j = 1}{min(k_j, d_j)}\times n) O(cnt×j=1nmin(kj,dj)×n) 很明显不可行
但是我们的目标仅仅是从临界下标 x − i − 1 x - i-1 xi1找到 m i n ( f [ p o s ] )   p o s ∈ [ x , i − 1 ] min(f[pos]) \ pos\in[x, i-1] min(f[pos]) pos[x,i1]
其实很显然的可以发现整个 d p dp dp数组是单调的(具体也没怎么证)
所以只要取临界值就行了
f [ i ] = m i n ( f [ i ] , f [ x ] + c j ) f[i]=min(f[i], f[x]+c_j) f[i]=min(f[i],f[x]+cj)
复杂度 O ( n × ∑ i = 1 m q i ) O(n\times \displaystyle\sum^{m}_{i=1}{q_i}) O(n×i=1mqi)

#include <bits/stdc++.h>

#define ll long long
#define int long long
#define pii pair<int, int>
#define rep(i, x, y) for(int i = x; i <= y; ++i)
#define dep(i, x, y) for(int i = x; i >= y; --i)
#define debug(x) cout << #x": " << x << endl;
#define ct cout << endl;

using namespace std;
const int maxn = 1e6+10;
const ll inf = 1e18;

template <typename _tp>
inline void read(_tp& x) {
    char ch = getchar(), sgn = 0;
    while (ch ^ '-' && !isdigit(ch)) ch = getchar();
    if (ch == '-') ch = getchar(), sgn = 1;
    for (x = 0; isdigit(ch); ch = getchar()) x = x * 10 + ch - '0';
    if (sgn) x = -x;
}

struct node{
    int d, k, c;
}ty[maxn];

int a[maxn], cnt;
int n, m, r;
int b[maxn], f[maxn];
signed main(){
    read(n), read(m), read(r);
    rep(i, 1, n) read(ty[i].d), read(ty[i].k), read(ty[i].c);
    while(m--){
        int p, q;
        read(p), read(q);
        while(q--) a[++cnt] = p; 
    }
    sort(a+1, a+1+cnt);
    rep(i, 1, cnt) f[i] = inf;
    rep(i, 1, n) b[i] = 1;
    rep(i, 1, cnt){
        //debug(i);
        f[i] = f[i-1] + r;
        rep(j, 1, n){
            while(a[b[j]] + ty[j].d <= a[i] || b[j] + ty[j].k <= i) b[j]++;
            f[i] = min(f[b[j] - 1] + ty[j].c, f[i]);
            //debug(f[i]);
        }
    }
    printf("%lld", f[cnt]);
    return 0;
}
  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值