noip模拟赛 思考熊的马拉松

【题目描述】

今年,n只思考熊参加了清华大学校园马拉松比赛。马拉松的赛道是环形的,每圈
的长度是A,完成比赛需要跑L圈。
比赛中,甲领先乙很长距离,绕过一圈或多圈后从后面追上了乙的现象叫做“套
圈”。套圈现象非常常见,例如:跑得比谁都快的saffah熊可以套某些熊L-1圈;
ufozgg熊经常进行日常耐力训练,套圈次数和被套圈次数基本持平;而Mulab作为一
只老年熊,则是被套L-1圈的那种。
与人不同的是,思考熊在跑步时都是匀速运动。wyx熊是这次比赛的计时员,他
统计了参赛的n只熊的速度v1v2,......,vn(其中最大的一个是saffah熊的速度)。现在
wyx熊希望你告诉他,当速度最快的saffah熊到达终点时,场上所有熊中总共发生了
多少次套圈现象。
注意:在saffah熊刚刚到达终点那一刻,如果甲恰好追上了乙,此时也算作甲将乙
套圈。

【输入格式】

从文件running.in中读入数据。
输入的第一行包含2个整数T;C,分别表示这个测试点内数据的组数和这个测试
点的编号。对于所有测试点,保证T = 10
每组数据的第一行包含3个正整数n;A;L,分别表示思考熊的只数,跑道每圈的长
度和完成比赛所需要的圈数。保证A;L<10^8
第二行包含n个正整数v1v2,......,vn,表示每只思考熊的速度。保证这些数互不
相同。

【输出格式】

输出到文件running.out中。
输出T行,分别表示每组数据中,所有熊发生的套圈总次数。

【样例输入】

4 0
2 1000 15
2 5
2 1000 13
9 4
5 1000 10
8 10 2 5 6
5 1000 17
8 10 2 5 7

【样例输出】

9
7
38
61

【数据范围】

n<=105,vi<=108

【题解】

套圈的圈数只取决于每个人跑了多少圈,所以答案为两两之间的圈数差向下取整
因为有圈数小数部分,所以无法通过前缀和O(n)计算
但是,我们可以把小数部分和整数部分分开做
整数部分用前缀和维护圈数,如果小数部分的差小于0,就再减一
比如一个跑了5.1圈,一个4.9圈,他们整数部分差为5-4=1,但是因为小数部分0.1-0.9<0,所以需要减一
所以需要找出两个数i,j,整数部分i>j,但小数i<j
这就是逆序对棵题了,树状数组就能搞定。
还有一个小优化,因为跑的圈数是l*vi/vmax,分母都相同,可以全部去掉转化成整数计算,避免精度误差

(之前用小数存被精度误差卡成狗了.......)

【代码】

#include<algorithm>
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<set>
using namespace std;
#define f(i,n) for(int i=1;i<=(n);i++)
#define ll long long
#define INF 1<<30
#define N 100010
#define c 32123
ll read()
{
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n;
ll v[N],f,l;
struct xj
{
	double n;
	int i;
}z[N];
double s;
bool cmp(xj a,xj b)
{
	if(a.n==b.n)return a.i>b.i;
	return a.n>b.n;
}
int szsz[N];
int lowbit(int x)
{
	return x&-x;
}
void ass(int k)
{
	while(k<=n)
	{
		szsz[k]++;
		k+=lowbit(k);
	}
}
int qj(int k)
{
	int ans=0;
	while(k>0)
	{
		ans+=szsz[k];
		k-=lowbit(k);
	}
	return ans;
}
int main()
{
	freopen("running.in","r",stdin);
	freopen("running.out","w",stdout);
	int t,C;
	scanf("%d%d",&t,&C);
	while(t--)
	{
	    scanf("%d%lld%lld",&n,&f,&l);
		f(i,n)v[i]=read();
		sort(v+1,v+n+1);
		ll ans=0,sum=0;
		f(i,n)
		{
			ll temp=l*v[i]/v[n];
			ans+=(i-1)*temp-sum;
			sum+=temp;
			z[i].n=l*v[i]-temp*v[n];
			z[i].i=i;
		}
		memset(szsz,0,sizeof(szsz));
		sort(z+1,z+n+1,cmp);
		f(i,n)
		{
			ans-=qj(z[i].i);
			ass(z[i].i);
		}
		printf("%lld\n",ans);
	}
}
原文地址:https://www.cnblogs.com/qwerfcxs/p/7802638.html