zoukankan      html  css  js  c++  java
  • 倍增或线段树,给出一个数,让它模一连串的数

                       J   Shopping

    链接:http://codeforces.com/gym/101201 

    题意:

    给出一系列商品的价格,下面再给出q个人浏览商品的起点到末尾,和他带上的钱,如果看到能买的商品就买最多个,输出每个人浏览后所剩余的钱

    分析:

    如果对于每个人都遍历一遍的话,最坏的情况超过了1e9。

    由于是取模运算,可以找到这个数列的第一个比他小的数,模它,比它大则无视。一个数最多模lgn下。

    接下来最重要的是找到第一个比V小的数的位置

    用倍增的方法存储一段数的最小值。

    然后再以lgn的速度求出从a开始,比v小的第一个数。

    ac代码1:倍增

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn=200000+10;
    #define LL long long
    LL num[maxn];
    LL Min[maxn][25];//Min[i][j]从第i个元素到i+2ej-1个元素的最小值
    int fin(LL V,int s)
    {
        for(int i=20;i>=1;i--)
        {
            while(Min[s][i]<=V&&Min[s][i-1]>V)
            {
                s+=(1<<(i-1));
            }
        }
        if(num[s]<=V)
           return s;
        else
           return maxn;
    }
    int main()
    {
        int n,q,s,o;
        LL V;
        cin>>n>>q;
        for(int i=1;i<=n;i++)
        {
            scanf("%I64d",&num[i]);
            Min[i][0]=num[i];
        }
        for(int j=1;j<=20;j++)//建立倍增数组
        for(int i=1;i<=n;i++)
        {
            if(i+(1<<(j-1))<=n)
                Min[i][j]=min(Min[i][j-1],Min[i+(1<<(j-1))][j-1]);
            else
                Min[i][j]=Min[i][j-1];
        }
        for(int i=1;i<=q;i++)
        {
            scanf("%I64d %d %d",&V,&s,&o);
            int k=fin(V,s);
            while(k<=o)
            {
                V%=num[k];
                k=fin(V,k+1);
            }
            printf("%I64d
    ",V);
        }
        return 0;
    }
    View Code

     ac代码2 :线段树

     1 #include <bits/stdc++.h>
     2 using namespace std;
     3 #define LL long long
     4 const int maxn=200000+10;
     5 struct Node
     6 {
     7     LL Min;
     8     int s,o;
     9 }node[maxn*4];
    10 LL num[maxn];
    11 void build(int s,int o,int xt)
    12 {
    13     node[xt].s=s,node[xt].o=o;
    14     int mid=(s+o)/2;
    15     if(s==o)
    16     {
    17         node[xt].Min=num[s];
    18         return ;
    19     }
    20     build(s,mid,xt*2);
    21     build(mid+1,o,xt*2+1);
    22     node[xt].Min=min(node[xt*2].Min,node[xt*2+1].Min);
    23 }
    24 int getnext(LL V,int ss ,int n)
    25 {
    26     if(ss>n)return 0;
    27     int xt=1;
    28     while(node[xt].s!=ss)
    29     {
    30         if(ss<=(node[xt].o+node[xt].s)/2)
    31             xt*=2;
    32         else xt=2*xt+1;
    33     }
    34     if(node[xt].Min<=V)
    35     {
    36         while(node[xt].o!=node[xt].s)
    37         {
    38             if(node[xt*2].Min<=V)
    39                 xt=2*xt;
    40             else
    41                 xt=2*xt+1;
    42         }
    43         return node[xt].o;
    44     }
    45     else return getnext(V,node[xt].o+1,n);
    46 }
    47 int main()
    48 {
    49     int n,q,a,b;
    50     LL V;
    51     cin>>n>>q;
    52     for(int i=1;i<=n;i++)
    53        scanf("%I64d",&num[i]);
    54     build(1,n,1);
    55     for(int i=1;i<=q;i++)
    56     {
    57          scanf("%I64d %d %d",&V,&a,&b);
    58          int next=getnext(V,a,n);
    59          while(next<=b&&next)
    60          {
    61              V%=num[next];
    62              next=getnext(V,next+1,n);
    63          }
    64          printf("%I64d
    ",V);
    65     }
    66     return 0;
    67 }
    View Code
  • 相关阅读:
    PHP 开发 APP 接口 学习笔记与总结
    Java实现 LeetCode 43 字符串相乘
    Java实现 LeetCode 43 字符串相乘
    Java实现 LeetCode 43 字符串相乘
    Java实现 LeetCode 42 接雨水
    Java实现 LeetCode 42 接雨水
    Java实现 LeetCode 42 接雨水
    Java实现 LeetCode 41 缺失的第一个正数
    Java实现 LeetCode 41 缺失的第一个正数
    Java实现 LeetCode 41 缺失的第一个正数
  • 原文地址:https://www.cnblogs.com/carcar/p/8918767.html
Copyright © 2011-2022 走看看