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);
	}
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM