• D


    题目:传送门

    题意:有 n 个店,一开始你在家,此时 t = 0,你可以花 1 单位时间从你家去任意的一个店,或者从某一个店去到另一个店。假设你在 t = x 的时候到达第 i 个店,那么你需要花 ai*x + bi 的时间在这个店买东西。现在问你在 T 单位时间内最多能去几个店买东西。

    1 <= n <= 2e5,  0 <= ai <= 1e9, 0 <= bi <= 1e9, 0 <= T <= 1e9

    思路:

    假设现在你有两个店 i, j,此时 t = x,若选择 i 比选择 j 更优,则需要满足:

    1 + ai * (x + 1) + bi + 1 + aj * (x + 1 + ai * (x + 1) + bi + 1) + bj   <   1 + aj * (x + 1) + bj + 1 + ai * (x + 1 + aj * (x + 1) + bj + 1) + bi

    化简一下,得到  aj * (bi + 1)  <  ai * (bj + 1)

    那么我们就可以按照上面的规则,排序。 然后 DP

    dp[ i ][ j ] 前 i 个店在 j 家店买东西需要花的最少的时间。

    然后第一维可以直接优化掉,直接当成 01 背包做 dp。

    但是这样的 DP 是 o(n^2) 的,需要考虑优化。

    可以根据 ai 的值进行分类,我们发现若 ai != 0,那么每次的时间都至少是成倍增加的,也就是说每在一个店买东西,时间就会 * 2,而 T <= 1e9,那么就是说对于 ai != 0 的店最多只能去 log(T) 个店买东西。

    那么我们直接对 ai != 0 的做一遍 dp,第二层 for 最多只有 log(T) 个,那么复杂度就很可观了。然后对每个 dp ,找一下剩下的时间能去多少个 ai == 0 的店即可。

    #include <bits/stdc++.h>
    #define LL long long
    #define mem(i, j) memset(i, j, sizeof(i))
    #define rep(i, j, k) for(int i = j; i <= k; i++)
    #define dep(i, j, k) for(int i = k; i >= j; i--)
    #define pb push_back
    #define make make_pair
    #define INF INT_MAX
    #define inf LLONG_MAX
    #define PI acos(-1)
    #define fir first
    #define sec second
    using namespace std;
    
    const int N = 2e5 + 10;
    
    pair < LL, LL > a[N], tmp;
    LL c[N];
    LL dp[100];
    
    bool cmp(pair < LL, LL > A, pair < LL, LL > B) {
        return A.fir * (B.sec + 1) > B.fir * (A.sec + 1);
    }
    
    void solve() {
    
        int n; LL T;
        scanf("%d %lld", &n, &T);
        int cnt1 = 0, cnt2 = 0;
        rep(i, 1, n) {
            scanf("%lld %lld", &tmp.fir, &tmp.sec);
            if(tmp.fir == 0) c[cnt2++] = tmp.sec + 1;
            else a[cnt1++] = tmp;
        }
    
        sort(c, c + cnt2);
        sort(a, a + cnt1, cmp);
    
        rep(i, 1, 30) dp[i] = T + 1;
        dp[0] = 0;
        rep(i, 1, cnt2 - 1) c[i] += c[i - 1];
    
        rep(i, 0, cnt1 - 1) {
            dep(j, 1, 30) {
                dp[j] = min(dp[j], (a[i].fir + 1) * (dp[j - 1] + 1) + a[i].sec);
            }
        }
    
        int ans = 0;
        rep(i, 0, 30) {
            if(dp[i] > T) continue;
            int add = 0;
            if(cnt2) add = upper_bound(c, c + cnt2, T - dp[i]) - c;
            ans = max(ans, i + add);
        }
        printf("%d
    ", ans);
        return ;
    }
    
    int main() {
    
        solve();
    
        return 0;
    }
    一步一步,永不停息
  • 相关阅读:
    oracle 常用函数
    css 让div 置于最顶层而不被其他东西挡住
    hibernate学习
    css居中参考
    log4j 将日志文件输出到web-inf下的解决办法
    mybatis 传递多个值的解决办法
    web项目中的路径问题
    sring 监听器
    struts2返回json字符串
    java 需要看的书籍
  • 原文地址:https://www.cnblogs.com/Willems/p/12448351.html
Copyright © 2020-2023  润新知