• gym101201J Shopping 二分+RMQ+数学性质


    题目传送门

    题目大意:

      给出n个商品的价格,排成一列,q次查询,每次查询如果你有x的钱,从l格子走到r格子,每种商品有无数个,能买就买,最后还会剩多少钱。

    思路:

      每一次买都要找离自己最近的且买的起的商品,这样可以二分区间,用线段树(rmq问题,可以用st表)找到离自己最近且买得起的商品,然后不断的向r逼近,最后就是答案。

      这个思路为什么不会超时的呢,因为可以想象,每次买完一个商品,你的剩余的钱最多也是这个商品价格的余数,而后面你买的起的商品价格肯定比这个小,所以稍微举几个例子就发现不会枚举几次的,有点像斐波那契数列的递减。(最坏的情况是商品价格为7,6,5,4,3,2,1,这样的时间复杂度也许会退化,但发现如果能走完这个过程,至少也要有28块钱,这个钱在买7的时候会直接用完,所以时间复杂度不会退化)。

      借用了队友写的代码,st表解决RMQ真的好短。

    #include <bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=200010;
    int n, q;
    ll a[N];
    
    ll dp[N][20];
    int mm[N];
    void init(int n, ll b[])
    {
        mm[0] = -1;
        for (int i = 1; i <= n; ++i)
        {
            mm[i] = ((i & (i - 1)) == 0) ? mm[i - 1] + 1: mm[i - 1];
            dp[i][0] = b[i];
        }
        for (int j = 1; j <= mm[n]; ++j)
            for (int i = 1; i + (1 << j) - 1 <= n; ++i)
                dp[i][j] = min(dp[i][j - 1], dp[i + (1 << (j - 1))][j - 1]);
    }
    
    ll query(int l, int r)
    {
        int k = mm[r - l + 1];
        return min(dp[l][k], dp[r - (1 << k) + 1][k]);
    }
    
    int main()
    {
        while (scanf("%d%d", &n, &q) != EOF)
        {
            for (int i = 1; i <= n; ++i) scanf("%lld", a + i); init(n, a); 
            ll v;
            for (int i = 1, l, r; i <= q; ++i)
            {
                scanf("%lld%d%d", &v, &l, &r);
                while (r - l >= 0)
                {
                    int ql = l, qr = r, tar = -1;
                    while (qr - ql >= 0)
                    {
                        int mid = (ql + qr) >> 1;
                        if (query(ql, mid) <= v)
                        {
                            qr = mid - 1;
                            tar = mid;
                        }
                        else
                            ql = mid + 1;
                    }
                    if (tar == -1) break;
                    v %= a[tar];
                    l = tar + 1;
                }
                printf("%lld
    ", v);
            }
        }
        return 0;
    }
    View Code
  • 相关阅读:
    单调栈
    单调队列
    线段树
    树状数组
    KMP模式匹配
    二分图最大匹配
    celery发送短信接口
    celery配置与基本使用
    celery介绍
    短信验证接口
  • 原文地址:https://www.cnblogs.com/mountaink/p/10094031.html
Copyright © 2020-2023  润新知