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;
}
由题意,我们可以得到 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;
}
相关文章推荐
- 用批处理解决数学问题的代码第1/4页
- C#数据结构之顺序表(SeqList)实例详解
- Lua教程(七):数据结构详解
- 解析从源码分析常见的基于Array的数据结构动态扩容机制的详解
- C#数据结构之队列(Quene)实例详解
- C#数据结构揭秘一
- C#数据结构之单链表(LinkList)实例详解
- 数据结构之Treap详解
- 用C语言举例讲解数据结构中的算法复杂度结与顺序表
- C#数据结构之堆栈(Stack)实例详解
- C#数据结构之双向链表(DbLinkList)实例详解
- JavaScript数据结构和算法之图和图算法
- Java数据结构及算法实例:冒泡排序 Bubble Sort
- Java数据结构及算法实例:插入排序 Insertion Sort
- Java数据结构及算法实例:考拉兹猜想 Collatz Conjecture
- java数据结构之java实现栈
- java数据结构之实现双向链表的示例
- Java数据结构及算法实例:选择排序 Selection Sort
- Java数据结构及算法实例:朴素字符匹配 Brute Force
- Java数据结构及算法实例:汉诺塔问题 Hanoi