倍增或线段树,给出一个数,让它模一连串的数

                   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
原文地址:https://www.cnblogs.com/carcar/p/8918767.html