"Tsinghua training 2017" My life has been a candle in the wind

Topic Link

problem analysis

Meaning of the questions is not difficult to understand.Why just the end of the rope is not fixed a nail

Then no idea, so we considered violence. Not difficult to find, after a time to find a circle, it will have less than half the length. So up to find \ (\ log L \) the second round. Each ring may find find \ (O (n) \) points to the need to find the next point \ (O (n) \) time. Thereby obtaining a false total time complexity is \ (O (Tm \ log L ^ n-2) \) . \ (3e10 \) feel \ (10 \) seconds is not OK.

Then consider the most number of operations to optimize, accelerate is to find the next point. First, pre-sorted in each polar angle of the center point, then the binary search first polar angle and then sweep a point, this can greatly speed up the time to find points. Although the upper limit of the time complexityThere should be no change, But not difficult to find this limit has been very loose. Then out of courage. Then the total time of only 1700 + ms? The slowest single point only 400 + ms? It is gone?

Here is an optimization proposal, it has not been achieved:Found violence by adding the above-described second point to optimize the total time 1500 + ms

1, the beginning of preprocessing directly \ (X \) , a polar angle \ (\ Alpha \) , just hit point \ (Y \) length. Thus a very loose at the start of the \ (O (n ^ 3) \) pretreatment, and only once for each back \ (O (\ log n) \) can. Such complexity is \ (O (Tm + Tn of ^. 3 \ log n-L \ log n-) \) . Probably \ (2E9 \) . The upper limit would be able to direct violence than at least one order of magnitude.

2, the length frequently used, apart from the function storage array, is constant optimization.

Reference program

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

void Main();
int main() {
    int TestCases;
    scanf("%d", &TestCases);
    for (; TestCases--;) Main();
    return 0;
}

const int Maxn = 510;
const double Eps = 1e-12;
inline int Cmp(const double x, const double y) {
    if (fabs(x - y) <= Eps)
        return 0;
    if (x - y > Eps)
        return 1;
    return -1;
}
struct point {
    double x, y;
    point() {}
    point(const double _x, const double _y) : x(_x), y(_y) {}
    inline void Read() {
        scanf("%lf%lf", &x, &y);
        return;
    }
    inline point operator-(const point Other) const { return point(x - Other.x, y - Other.y); }
    inline double operator*(const point Other) const { return x * Other.y - Other.x * y; }
    inline point operator*(const double Other) const { return point(x * Other, y * Other); }
    inline double Len() const { return sqrt(x * x + y * y); }
};
struct member {
    int Quadrant, Index;
    point Point;
    member() {}
    member(const int _Index, const point _Point) {
        Index = _Index;
        Point = _Point;
        Quadrant = (Cmp(Point.y, 0.0) != 0) ? Cmp(Point.y, 0.0) : Cmp(Point.x, 0.0);
        return;
    }
    inline bool operator<(const member Other) const {
        if (Quadrant != Other.Quadrant)
            return Quadrant < Other.Quadrant;
        double Temp = Cmp(Point * Other.Point, 0.0);
        return Temp < 0 || Temp == 0 && Point.Len() > Other.Point.Len();
    }
};
int n, m;
point Point[Maxn];
member Relation[Maxn][Maxn];
int RelationSize[Maxn];
point Start, Direction;
double Length;
int Stack[Maxn], Vis[Maxn][Maxn];

void Init();
int Work();
void Main() {
    Init();
    for (int i = 1; i <= m; ++i) printf("%d\n", Work());
    return;
}

void Init() {
    scanf("%d%d", &n, &m);
    for (int i = 1; i <= n; ++i) Point[i].Read();
    for (int i = 1; i <= n; ++i) {
        RelationSize[i] = 0;
        for (int j = 1; j <= n; ++j)
            if (i != j)
                Relation[i][++RelationSize[i]] = member(j, Point[j] - Point[i]);
        sort(Relation[i] + 1, Relation[i] + RelationSize[i] + 1);
    }
    return;
}

int Find(const int Index, const point Direction);
int Work() {
    Start.Read();
    Direction.Read();
    scanf("%lf", &Length);
    Direction = Direction - Start;
    Direction = Direction * (Length / Direction.Len());

    for (int i = 1; i <= n; ++i) Relation[0][i] = member(i, Point[i] - Start);
    RelationSize[0] = n;
    sort(Relation[0] + 1, Relation[0] + n + 1);

    int First = Find(0, Direction);
    if (First == -1)
        return 1;
    Length -= Relation[0][First].Point.Len();
    Direction = Relation[0][First].Point * (Length / Relation[0][First].Point.Len());
    First = Relation[0][First].Index;

    int Second = Find(First, Direction);
    if (Second == -1)
        return 2;
    Length -= Relation[First][Second].Point.Len();
    Direction = Relation[First][Second].Point * (Length / Relation[First][Second].Point.Len());
    Second = Relation[First][Second].Index;

    int Ans = 2;
    for (int Time = 1;; ++Time) {
        Stack[0] = 0;
        Stack[++Stack[0]] = First;
        Stack[++Stack[0]] = Second;

        for (;;) {
            int Next = Find(Second, Direction);
            if (Next == -1)
                return Ans + Stack[0] - 1;
            Length -= Relation[Second][Next].Point.Len();
            Direction = Relation[Second][Next].Point * (Length / Relation[Second][Next].Point.Len());
            Next = Relation[Second][Next].Index;
            Stack[++Stack[0]] = Next;
            First = Second;
            Second = Next;

            if (Vis[First][Second] == Time)
                break;
            Vis[First][Second] = Time;
        }
        --Stack[0];

        int Pos;
        for (Pos = 0; Pos < Stack[0]; ++Pos)
            if (Stack[Pos] == First && Stack[Pos + 1] == Second)
                break;
        double TotalLength = 0;
        for (int i = Pos; i < Stack[0]; ++i) TotalLength += (Point[Stack[i + 1]] - Point[Stack[i]]).Len();

        Ans += Stack[0] - 1;
        int Times = (int)floor(Length / TotalLength);
        Ans += Times * (Stack[0] - Pos);
        Length -= TotalLength * Times;
        Direction = Direction * (Length / Direction.Len());
    }
    return Ans;
}

int Find(const int Index, const point Dir) {
    member Direction = member(0, Dir);
    int Size = RelationSize[Index];
    int Ans = lower_bound(Relation[Index] + 1, Relation[Index] + Size + 1, Direction) - Relation[Index];
    if (Ans > Size)
        Ans = 1;
    for (int i = 1; i <= Size; ++i) {
        if (Cmp(Dir.Len(), Relation[Index][Ans].Point.Len()) == 1)
            return Ans;
        ++Ans;
        if (Ans > Size)
            Ans = 1;
    }
    return -1;
}

Guess you like

Origin www.cnblogs.com/chy-2003/p/11297535.html