LA3905流星
題意:
? ? ? 在一個二維平面上有n個流星,每個流星有自己的初始位置和速度,有一個照相機,張相機的可視范圍是一個矩形框,左下角(0,0)右上角(w ,h),然后問你相機的矩形內出現的最多的流星數是多少??
思路:
? ? ? 感覺是一道很不錯的題目,想到流星數目,第一反應就是可以把他轉化成時間段,我們求出每個流星的進入相機時間,和出相機時間,這樣就會得到一個時間段,流星的最大
數量也就是時間段的最大重疊部分,這個不解釋了應該不難理解,現在問題就來了,我們怎么求得所有的時間段呢?一開始我也感覺很麻煩,然后在白書上學了一個比較方便的方法,我們求時間段可以先把流星分解了,x,y單獨算,進入的時間肯定是進x進y的最大值,出去的時間肯定是出x,出y的最小值,這樣我們分別求完之后就ok了,如果L>=R就證明沒有在相機范圍內出現過,下面給出求L,R的代碼
void Update(int x ,int a ,int w ,double& L ,double& R)
{
? ?if(a == 0)
? ?{
? ? ? ?if(x <= 0 || x >= w) R = L - 1; //永遠也進步了相機
? ?}
? ?else if(a > 0)//往上跑?
? ?{
? ? ? L = Max(L ,-(double)x / a);
? ? ? R = Min(R ,(double)(w - x) / a);
? ?}
? ?else//往下跑
? ?{
? ? ? L = Max(L ,(double)(w - x) / a);//理解不了的注意這里的a是負的
? ? ? R = Min(R ,-(double)x / a);?
? ?}
? ? ? ? ? ?
}
求x,y的時候都是用的上面的那個,只不過傳的參數不一樣罷了,具體細節可以看代碼。
? 這樣我們就得到了所有流星的時間段L,R(L>=R的是不滿足的,直接丟棄),然后就是求區間的最大重疊面積了,這個也比較好求,如果你不嫌麻煩可以寫線段樹貪心去求,時間復雜度是O(n*log(n))的,不過有一個更省事更快的方法,就是掃面線法O(n)<其實這么說有漏洞,因為掃描線涉及到排序,排序是O(n*log(n))的,這個地方大家知道就行了>,我們可以把所有端點都扔進結構體數組里,然后按照時間從小到大排序,如果時間相等那么就后端點在前面(這樣的原因是題目中說在相機邊框上的不算,如果算的話就入端點在前面),排序之后直接掃一遍,遇到前端點就++,后端點就--,過程中最大的值就是答案,這個應該很好理解,不理解的在紙上畫一畫,每次變化的時候都是在端點上變化的,這個就是經典的掃描線想法,掃描線也可以配合著線段樹應用,求重疊面積,體積,周長啥的。這個題目還有一個小小的優化(白書上說的),我們可以躲開浮點運算,因為整個程序里涉及到的除法就是除以速度,速度的范圍是絕對值<=10,那么我們直接把被除數擴大1,2,3..10的最小公倍數2520倍就行了,這樣保證都是整除,至于為什么我想不用我解釋了。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 100000 + 10
using namespace std;
typedef struct
{
? ? int mk;
? ? double time;
}NODE;
NODE node[N+N];
bool camp(NODE a ,NODE b)
{
? ? ?return a.time < b.time || a.time == b.time && a.mk < b.mk;
}
double Max(double x ,double y)
{
? ? return x > y ? x : y;
}
double Min(double x ,double y)
{
? ? return x < y ? x : y;
}
void Update(int x ,int a ,int w ,double& L ,double& R)
{
? ?if(a == 0)
? ?{
? ? ? ?if(x <= 0 || x >= w) R = L - 1;
? ?}
? ?else if(a > 0)?
? ?{
? ? ? L = Max(L ,-(double)x / a);
? ? ? R = Min(R ,(double)(w - x) / a);
? ?}
? ?else
? ?{
? ? ? L = Max(L ,(double)(w - x) / a);
? ? ? R = Min(R ,-(double)x / a);?
? ?}
? ? ? ? ? ?
}
int main ()
{
? ? int t ,w ,h ,n ,i;
? ? int x ,y ,a ,b;
? ? scanf("%d" ,&t);
? ? while(t--)
? ? {
? ? ? ?scanf("%d %d" ,&w ,&h);
? ? ? ?scanf("%d" ,&n);
? ? ? ?int nowid = 0;
? ? ? ?for(i = 1 ;i <= n ;i ++)
? ? ? ?{
? ? ? ? ? scanf("%d %d %d %d" ,&x ,&y ,&a ,&b);
? ? ? ? ? double L = 0 ,R = 999999999;
? ? ? ? ? Update(x ,a ,w ,L ,R);
? ? ? ? ? Update(y ,b ,h ,L ,R);
? ? ? ? ? if(L < R)
? ? ? ? ? {
? ? ? ? ? ? ?node[++nowid].time = L;
? ? ? ? ? ? ?node[nowid].mk = 1;
? ? ? ? ? ? ?node[++nowid].time = R;
? ? ? ? ? ? ?node[nowid].mk = -1;
? ? ? ? ? }
? ? ? ?}
? ? ? ?int Ans = 0;
? ? ? ?sort(node + 1 ,node + nowid + 1 ,camp);
? ? ? ?int sum = 0;
? ? ? ?for(i = 1 ;i <= nowid ;i ++)
? ? ? ?{
? ? ? ? ? sum += node[i].mk;
? ? ? ? ? if(Ans < sum) Ans = sum;
? ? ? ?}
? ? ? ?printf("%d\n" ,Ans);
? ? }
? ? return 0; ?
}
? ?
//排除浮點型運算
void Update(int x ,int a ,int w ,int& L ,int& R)
{
? ?if(a == 0)
? ?{
? ? ? ?if(x <= 0 || x >= w) R = L - 1;
? ?}
? ?else if(a > 0)?
? ?{
? ? ? L = Max(L ,-x * 2520 / a);
? ? ? R = Min(R ,(w - x) * 2520 / a);
? ?}
? ?else
? ?{
? ? ? L = Max(L ,(w - x) * 2520/ a);
? ? ? R = Min(R ,-x * 2520/ a);?
? ?}
? ? ? ? ? ?
}
? ? ? 在一個二維平面上有n個流星,每個流星有自己的初始位置和速度,有一個照相機,張相機的可視范圍是一個矩形框,左下角(0,0)右上角(w ,h),然后問你相機的矩形內出現的最多的流星數是多少??
思路:
? ? ? 感覺是一道很不錯的題目,想到流星數目,第一反應就是可以把他轉化成時間段,我們求出每個流星的進入相機時間,和出相機時間,這樣就會得到一個時間段,流星的最大
數量也就是時間段的最大重疊部分,這個不解釋了應該不難理解,現在問題就來了,我們怎么求得所有的時間段呢?一開始我也感覺很麻煩,然后在白書上學了一個比較方便的方法,我們求時間段可以先把流星分解了,x,y單獨算,進入的時間肯定是進x進y的最大值,出去的時間肯定是出x,出y的最小值,這樣我們分別求完之后就ok了,如果L>=R就證明沒有在相機范圍內出現過,下面給出求L,R的代碼
void Update(int x ,int a ,int w ,double& L ,double& R)
{
? ?if(a == 0)
? ?{
? ? ? ?if(x <= 0 || x >= w) R = L - 1; //永遠也進步了相機
? ?}
? ?else if(a > 0)//往上跑?
? ?{
? ? ? L = Max(L ,-(double)x / a);
? ? ? R = Min(R ,(double)(w - x) / a);
? ?}
? ?else//往下跑
? ?{
? ? ? L = Max(L ,(double)(w - x) / a);//理解不了的注意這里的a是負的
? ? ? R = Min(R ,-(double)x / a);?
? ?}
? ? ? ? ? ?
}
求x,y的時候都是用的上面的那個,只不過傳的參數不一樣罷了,具體細節可以看代碼。
? 這樣我們就得到了所有流星的時間段L,R(L>=R的是不滿足的,直接丟棄),然后就是求區間的最大重疊面積了,這個也比較好求,如果你不嫌麻煩可以寫線段樹貪心去求,時間復雜度是O(n*log(n))的,不過有一個更省事更快的方法,就是掃面線法O(n)<其實這么說有漏洞,因為掃描線涉及到排序,排序是O(n*log(n))的,這個地方大家知道就行了>,我們可以把所有端點都扔進結構體數組里,然后按照時間從小到大排序,如果時間相等那么就后端點在前面(這樣的原因是題目中說在相機邊框上的不算,如果算的話就入端點在前面),排序之后直接掃一遍,遇到前端點就++,后端點就--,過程中最大的值就是答案,這個應該很好理解,不理解的在紙上畫一畫,每次變化的時候都是在端點上變化的,這個就是經典的掃描線想法,掃描線也可以配合著線段樹應用,求重疊面積,體積,周長啥的。這個題目還有一個小小的優化(白書上說的),我們可以躲開浮點運算,因為整個程序里涉及到的除法就是除以速度,速度的范圍是絕對值<=10,那么我們直接把被除數擴大1,2,3..10的最小公倍數2520倍就行了,這樣保證都是整除,至于為什么我想不用我解釋了。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define N 100000 + 10
using namespace std;
typedef struct
{
? ? int mk;
? ? double time;
}NODE;
NODE node[N+N];
bool camp(NODE a ,NODE b)
{
? ? ?return a.time < b.time || a.time == b.time && a.mk < b.mk;
}
double Max(double x ,double y)
{
? ? return x > y ? x : y;
}
double Min(double x ,double y)
{
? ? return x < y ? x : y;
}
void Update(int x ,int a ,int w ,double& L ,double& R)
{
? ?if(a == 0)
? ?{
? ? ? ?if(x <= 0 || x >= w) R = L - 1;
? ?}
? ?else if(a > 0)?
? ?{
? ? ? L = Max(L ,-(double)x / a);
? ? ? R = Min(R ,(double)(w - x) / a);
? ?}
? ?else
? ?{
? ? ? L = Max(L ,(double)(w - x) / a);
? ? ? R = Min(R ,-(double)x / a);?
? ?}
? ? ? ? ? ?
}
int main ()
{
? ? int t ,w ,h ,n ,i;
? ? int x ,y ,a ,b;
? ? scanf("%d" ,&t);
? ? while(t--)
? ? {
? ? ? ?scanf("%d %d" ,&w ,&h);
? ? ? ?scanf("%d" ,&n);
? ? ? ?int nowid = 0;
? ? ? ?for(i = 1 ;i <= n ;i ++)
? ? ? ?{
? ? ? ? ? scanf("%d %d %d %d" ,&x ,&y ,&a ,&b);
? ? ? ? ? double L = 0 ,R = 999999999;
? ? ? ? ? Update(x ,a ,w ,L ,R);
? ? ? ? ? Update(y ,b ,h ,L ,R);
? ? ? ? ? if(L < R)
? ? ? ? ? {
? ? ? ? ? ? ?node[++nowid].time = L;
? ? ? ? ? ? ?node[nowid].mk = 1;
? ? ? ? ? ? ?node[++nowid].time = R;
? ? ? ? ? ? ?node[nowid].mk = -1;
? ? ? ? ? }
? ? ? ?}
? ? ? ?int Ans = 0;
? ? ? ?sort(node + 1 ,node + nowid + 1 ,camp);
? ? ? ?int sum = 0;
? ? ? ?for(i = 1 ;i <= nowid ;i ++)
? ? ? ?{
? ? ? ? ? sum += node[i].mk;
? ? ? ? ? if(Ans < sum) Ans = sum;
? ? ? ?}
? ? ? ?printf("%d\n" ,Ans);
? ? }
? ? return 0; ?
}
? ?
//排除浮點型運算
void Update(int x ,int a ,int w ,int& L ,int& R)
{
? ?if(a == 0)
? ?{
? ? ? ?if(x <= 0 || x >= w) R = L - 1;
? ?}
? ?else if(a > 0)?
? ?{
? ? ? L = Max(L ,-x * 2520 / a);
? ? ? R = Min(R ,(w - x) * 2520 / a);
? ?}
? ?else
? ?{
? ? ? L = Max(L ,(w - x) * 2520/ a);
? ? ? R = Min(R ,-x * 2520/ a);?
? ?}
? ? ? ? ? ?
}
總結
- 上一篇: LA3902网络
- 下一篇: LA3971组装电脑