【题目背景】
一只乌鸦在自娱自乐,它在面前放了n个有魔力的水缸,水缸里装有无限的水。
【题目描述】
他准备从第1个水缸飞到第n个水缸,共m次。在飞过一个水缸的过程中,如果他能够得着水缸里的水,即水缸口到水面距离小于等于乌鸦能够得着的深度,那它就会喝水缸里的水。每喝一次水,所有水缸里的水位都会下降,第i个水缸里的水位会下降Ai,注意喝水是瞬间的,如果乌鸦刚好够得着,但喝完之后够不着,也视为喝到一次,水位也会相应的下降。
Input
共有3行。第一行有三个正整数n、m和x,用空格隔开。n表示水缸的数量,m表示乌鸦飞的次数,x表示乌鸦能够得着的深度。第二行,有n个用空格隔开的正整数,第i个数为第i个水缸中水缸口到水面的距离Wi。第三行,有n个用空格隔开的正整数,第i个为Ai。
Output
只有一行,这一行只有一个正整数,为这只乌鸦能喝到水的次数。
Sample Input
5 2 20
15 14 13 12 12
1 1 1 1 1
15 14 13 12 12
1 1 1 1 1
Sample Output
9
【数据范围】
100%的数据,0<n≤100000,0<m≤100000,0<x≤2000000000,0<Wi≤2000000000,0<Ai≤200。
【数据范围】
100%的数据,0<n≤100000,0<m≤100000,0<x≤2000000000,0<Wi≤2000000000,0<Ai≤200。
从数据来看真心不好想到正解,但从数据来看,真心水。一个链表能骗95分,然而我明明95,却担心T太多,毕竟理论连50分都拿不到。于是乎我瞎打了一个上去,把95分改成了50分,名副其实的250。
老师发了正解,由于里面很多都没说明白,去网上找了对应的标程理解,看了半天也没看懂,最后惊喜的发现标程本身就是错的,严重鄙视这种不负责任的行为。
无奈,想呵呵酵母菌学他的打法(在这里%一发,他是考试的时候直接A掉的)。
我们先把所有可能能喝到的筛出来,剪一下枝,然后将他们按照可以喝的次数-下标+1存储,也就是他可以在前面的水都被喝掉情况下再被喝几次。我们每一轮都去扫线段树的最小值,然后将它与我们现在的ans比对,如果它比ans大,那么说明所有水缸都可以被再喝一次,不然我们就一次剃掉左边的最小值,然后检查,最后对于答案加上场上现在还有多少水缸。
1 #include <iostream> 2 #include <cstdlib> 3 #include <cstdio> 4 #include <cstring> 5 #include <queue> 6 #include <algorithm> 7 #include <cmath> 8 #include <map> 9 #define N 100005 10 using namespace std; 11 int n,m,zz; 12 long long l,w[N],a[N],b[N]; 13 long long ans; 14 struct no 15 { 16 int left,mid,right; 17 long long lazy,mn; 18 }node[N*4]; 19 void build(int left,int right,int x) 20 { 21 node[x].left=left,node[x].right=right; 22 if(left==right) 23 { 24 node[x].mn=b[left]-left+1; 25 return; 26 } 27 int mid=(left+right)>>1; 28 node[x].mid=mid; 29 build(left,mid,2*x); 30 build(mid+1,right,2*x+1); 31 node[x].mn=min(node[x*2].mn,node[2*x+1].mn); 32 } 33 void pushdown(int x) 34 { 35 if(node[x].lazy) 36 { 37 node[2*x].lazy+=node[x].lazy; 38 node[2*x+1].lazy+=node[x].lazy; 39 node[2*x].mn+=node[x].lazy; 40 node[2*x+1].mn+=node[x].lazy; 41 node[x].lazy=0; 42 } 43 } 44 int js; 45 int del(int x,int z) 46 { 47 if(node[x].left==node[x].right) 48 { 49 node[x].mn=0x7fffffff; 50 js--; 51 return node[x].left; 52 } 53 pushdown(x); 54 int ans=0; 55 if(node[x*2].mn<=z) 56 ans=del(2*x,z); 57 else ans=del(2*x+1,z); 58 node[x].mn=min(node[2*x].mn,node[2*x+1].mn); 59 return ans; 60 } 61 void add(int left,int right,int x,int z) 62 { 63 if(node[x].left==left&node[x].right==right) 64 { 65 node[x].lazy+=z; 66 node[x].mn+=z; 67 return; 68 } 69 pushdown(x); 70 int mid=node[x].mid; 71 if(left>mid)add(left,right,2*x+1,z); 72 else if(right<=mid)add(left,right,2*x,z); 73 else add(left,mid,2*x,z),add(mid+1,right,2*x+1,z); 74 node[x].mn=min(node[2*x].mn,node[2*x+1].mn); 75 } 76 int main() 77 { 78 scanf("%d%d%lld",&n,&m,&l); 79 for(int i=1;i<=n;i++) 80 scanf("%lld",&w[i]); 81 for(int i=1;i<=n;i++) 82 scanf("%lld",&a[i]); 83 for(int i=1;i<=n;i++) 84 { 85 if((l-w[i])/a[i]+1>0) 86 { 87 zz++; 88 b[zz]=(l-w[i])/a[i]+1; 89 } 90 } 91 build(1,zz,1); 92 n=zz; 93 long long ans=0;js=n; 94 for(int i=1;i<=m;i++) 95 { 96 if(node[1].mn>ans)ans+=js; 97 else 98 { 99 while(node[1].mn<=ans) 100 { 101 int t=del(1,ans); 102 add(t,n,1,1); 103 } 104 ans+=js; 105 } 106 } 107 printf("%lld\n",ans); 108 return 0; 109 }