//請忽略我把牛看作羊....
由題意,我們可以得到 t*vi-t*vj=kC.那麼i,j相遇的次數就是最大的k(整數).爲了得到最大的k就要使t最大,而tmax=L*C/vmax.
那麼 把式子整理得到:
k=L*(vi-vj)/vmax.(向下取整)
對於第i只,它和速度比它小的每一隻羊相遇的次數都能確定,
常見的思路就是運用前綴和把式子累加,但由於k是每兩隻羊之間運算取整的結果,加到一起後,答案會發生變化.所以不能單單相加運算,我們可以算出累加算法對正確答案產生的影響.
先看兩個式子:
A1=[a*t+b-(c*t+d)]/t 與A2= (a*t+b)/t-(c*t+d)/t(a,c爲整數;b,d∈[0,t-1])
變形得:
A1=[(a-c)*t+b-d]/t
A2=a-c.
只有當b-d<0,即b<d時A1!=A2且A1=A2-1.
現在我們來看原題:
當L*C*(vi-vj)/(vmax*C)變爲
( L*C*vi)/(vmax*C)- ( L*C*vi)/(vmax*C)時,答案會不會改變取決於L*C*vi和L*C*vj除vmax*C的餘數大小關係.
如果前者小於後者,答案要減去1.
我們按照速度從大到小枚舉每一隻羊i
對於羊i的答案 =(i-1)*L*vi/vmax-L*sumv[i-1]/vmax-cnt.
此處cnt表示餘數大於羊i的餘數,且速度小於羊i的個數.
我們將餘數x排序.再用樹狀數組維護v<vi,且x>xi的個數就可以啦.
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define ll long long
using namespace std;
const int M=1e5+5;
const int N=1e6+5;
int n,L,vmx,C;
int val[M],tot=0;
struct node{
int v,p;
ll mod;
}A[M];
void add(int x){//樹狀數組更新
while(x<=tot){
val[x]++;
x+=x&(-x);
}
}
int sum(int x){//樹狀數組求和
int res=0;
while(x>0){
res+=val[x];
x-=x&(-x);
}
return res;
}
bool cmp1(node a,node b){ return a.v<b.v; }//按照速度排序
bool cmp2(node a,node b){ return a.mod<b.mod; }// 按照餘數排序
int main(){
int i,j;
scanf("%d %d %d",&n,&L,&C);
for(i=1;i<=n;i++){
scanf("%d",&A[i].v);
vmx=max(vmx,A[i].v);//z找到最大的速度
}
for(i=1;i<=n;i++)A[i].mod=1ll*L*C*A[i].v%(1ll*C*vmx);//
sort(A+1,A+1+n,cmp2);
for(i=1;i<=n;i++){
tot++;
for(j=i;j<=n;j++){
if(A[j].mod!=A[i].mod)break;
A[j].p=tot;
}
i=j-1;
}
sort(A+1,A+1+n,cmp1);
ll sum_pre=0,res=0;
for(i=1;i<=n;i++){
ll tmp=1ll*L*A[i].v/vmx;
ll ans=tmp*(i-1)-sum_pre+sum(A[i].p)-i+1;
sum_pre+=tmp;
add(A[i].p);
res+=ans;
}
cout<<res<<endl;
return 0;
}