您的位置:首页 > 运维架构

USACO2011Open Silver Running Laps题解

2016-06-28 17:07 211 查看
//请忽略我把牛看作羊....

由题意,我们可以得到 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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息