cf595d


題意:給出一個輪子,上面有一個隨着它轉動的傳感器在圓周上,給出一個指定距離m,和輪子向前行進的速度v以及輪子的半徑r。問讓傳感器通過該距離最少需要多少時間。

分析:首先我們列出傳感器行進距離與時間的輪子行進距離的關系:f(c) = c+r*sin(c/r)。其中c是距離,r是半徑。該公式表示傳感器從輪子正上方開始運行索性進的距離。

我們可以先去除一種情況,就是距離m是直徑2r的整數倍,那么傳感器在開始點和結束點所處的角度是相同的,無論從哪個角度開始所需的時間都是一樣的。

我們只考慮非整數倍的情況。

要看傳感器行進速度的變化,我們需要對這個函數f關於c進行求導。

求得導數是:f'(c) = 1+cos(c/r)。這就是傳感器速度的函數。而這個函數圖像與x軸所夾的面積就是行進距離。

那么,我們現在的任務就變成了在這個圖像上截取一段,使得與x軸所夾的面積是m,且要保證我們截取的橫向長度最短。(因為速度是一定的,距離和時間成正比)

假設我們截取了x=a到x=b。那么一定有f'(a)=f'(b)。如果兩者不等,例如f'(a)<f'(b),我只要將右邊緣向右平移一點點,保證面積不變的話,就需要將左邊緣向右平移更多。

因為我們如果把這個增量看成小長方體,如果左右平移量相等,f'(a)<f'(b)導致右邊進來的就比左邊進來的長方體高,那面積就變了。

既然f'(a)=f'(b),就一定a在圖像的遞增區域,b在遞減區域,否則還會出現上面的情況,或者就是m是2r的整數倍。

也就是說兩邊緣必須對稱,也就是說選區的中間是最高點或者最低點。我們只需要對兩種情況分別進行二分查找即可。

二分查找的時候查找輪子的行進長度,每次觀察f(c)>=m/2是否成立。

 

二分查找有個需要特別注意的地方。如果每次只是限定L和R的差值是不行的。差值設大了就會出現WA,設小了會TLE。

需要限定二分迭代的次數為50次左右。不知道是不是其他的比賽或者OJ也有這種情況。

#include <cstdio>
#include <algorithm>
#include <cmath>
using namespace std;

#define d(x) 

#define zero(x) (((x)>0?(x):-(x))<eps)
#define eps 1.0E-8

int double_cmp(double a)
{
    if (zero(a))
        return 0;
    return a > 0 ? 1 : -1;
}

int n, radius, v;
int dist;

bool top_ok(double bike_dist)
{
    double ret = bike_dist + radius * sin(bike_dist / radius);
    return double_cmp(ret * 2.0 - dist) >= 0;
}

bool bottom_ok(double bike_dist)
{
    double ret = bike_dist - radius * sin(bike_dist / radius);
    return double_cmp(ret * 2.0 - dist) >= 0;
}

double binary_search(bool (*ok)(double))
{
    double l = max(0.0, dist / 2.0 - 2 * radius);
    double r = dist / 2.0 + 2 * radius;
    int cnt = 0;
    while (double_cmp(r - l) > 0)
    {
        double mid = (l + r) / 2;
        if (ok(mid))
            r = mid;
        else
            l = mid;
        cnt++;
        if (cnt > 100)
            break;
    }
    d(printf("%.2f\n", l / radius / 2 / 3.14));
    return l;
}

double work()
{
    double time_top = binary_search(&top_ok) / v;
    double time_bottom = binary_search(&bottom_ok) / v;
    d(printf("%.2f %.2f\n", time_top, time_bottom));
    return min(time_top, time_bottom) * 2;
}

int main()
{
    scanf("%d", &n);
    scanf("%d%d", &radius, &v);
    for (int i = 0; i < n; i++)
    {
        int a, b;
        scanf("%d%d", &a, &b);
        dist = b - a;
        printf("%.12f\n", work());
    }
    return 0;
}
View Code

 


免責聲明!

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



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