【USACO 2012 Open】Running Laps(树状数组)
53 奶牛赛跑
约翰有 N 头奶牛,他为这些奶牛准备了一个周长为 C 的环形跑牛场。所有奶牛从起点同时起跑,
奶牛在比赛中总是以匀速前进的,第 i 头牛的速度为 Vi。只要有一头奶牛跑完 L 圈之后,比赛就立
即结束了。
有时候,跑得快的奶牛可以比跑得慢的奶牛多绕赛场几圈,从而在一些时刻超过慢的奶牛。这就
是最令观众激动的套圈事件了。请问在整个比赛过程中,套圈事件一共会发生多少次呢?
输入格式
• 第一行:三个整数 N, L 和 C, 1 ≤ N ≤ 105 , 1 ≤ L ≤ 25000 , 1 ≤ C ≤ 25000
• 第二行到第 N + 1 行:第 i + 1 行有一个整数 Vi, 1 ≤ Vi ≤ 106
输出格式
• 单个整数:表示整个比赛过程中,套圈的次数之和
样例输入
4 2 100
20
100
70
1
样例输出
4
解释
两头速度快的奶牛会超过两头速度慢的奶牛
各一次
【分析】
稍微思考一下的题我就不会了么- -
算出每头牛跑的圈数(double),因为都是匀速,要超过完整的一圈必须圈数完整的多1。
但是n^2就会很慢。
可以拆成整数部分和小数部分来做,排个序,整数部分先直接减掉前面的,小数部分求逆序对,然后在ans里面减掉。
要用long long
代码如下:
1 #include<cstdio> 2 #include<cstdlib> 3 #include<cstring> 4 #include<iostream> 5 #include<algorithm> 6 #include<queue> 7 #include<cmath> 8 using namespace std; 9 #define Maxn 100010 10 #define LL long long 11 12 struct node 13 { 14 double a; 15 LL id; 16 }t[Maxn]; 17 18 LL c[Maxn],v[Maxn]; 19 20 LL mymax(LL x,LL y) {return x>y?x:y;} 21 bool cmp(node x,node y) {return x.a<y.a;} 22 bool cmp2(node x,node y) {return x.id<y.id;} 23 24 LL n; 25 26 void add(LL x,LL y) 27 { 28 for(LL i=x;i<=n;i+=i&(-i)) 29 c[i]+=y; 30 } 31 32 LL get_ans(LL x) 33 { 34 LL ans=0; 35 for(LL i=x;i>=1;i-=i&(-i)) 36 ans+=c[i]; 37 return ans; 38 } 39 40 int main() 41 { 42 LL l,nc; 43 scanf("%lld%lld%lld",&n,&l,&nc); 44 for(LL i=1;i<=n;i++) scanf("%d",&v[i]); 45 sort(v+1,v+1+n); 46 LL sum=0,ans=0; 47 for(LL i=1;i<=n;i++) 48 { 49 t[i].a=(double)(l*1.0*v[i]/v[n]); 50 LL x=(LL)(t[i].a); 51 ans+=(i-1)*x-sum; 52 sum+=x; 53 t[i].a=t[i].a-x; 54 t[i].id=i; 55 } 56 sort(t+1,t+1+n,cmp); 57 LL p=1; 58 double now=t[1].a; 59 t[1].a=1; 60 for(LL i=2;i<=n;i++) 61 { 62 if(t[i].a-now>0.000001) p++,now=t[i].a; 63 t[i].a=p; 64 } 65 sort(t+1,t+1+n,cmp2); 66 memset(c,0,sizeof(c)); 67 for(LL i=n;i>=1;i--) 68 { 69 LL x=(LL)(t[i].a); 70 ans-=get_ans(x-1); 71 add(x,1); 72 } 73 printf("%lld\n",ans); 74 return 0; 75 }
2016-10-28 08:35:28