USACO2011Open Silver Running Laps題解

//請忽略我把牛看作羊....

由題意,我們可以得到 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;
}

發佈了39 篇原創文章 · 獲贊 2 · 訪問量 2萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章