倍增或线段树,给出一个数,让它模一连串的数
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\n",V); } return 0; }
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\n",V); 65 } 66 return 0; 67 }