1. 程式人生 > >清北學堂國慶day4解題報告

清北學堂國慶day4解題報告

bsp 二分 0.00 square 距離 級別 左右 最終 3.0

Day4解題報告

張炳琪

時間安排::

T1:30分鐘寫了個分塊暴力

T2:一個半小時寫了個枚舉暴力

T3:一個小時寫了個搜索暴力

答題情況和錯誤分析::

T1 100

由於數據是隨機的,其實n方暴力就可以,不需要用分塊也能過

T260

考場上寫了個n^3 * log10000的算法,過了60分,正解挺難想的,也不會寫

T310

有點想當然了,將距離理解成了二次函數求極值,沒打部分分(而且求極值的方法我不會,用搜索寫的)

Tot::170

題目解析:

T1

對於每個位置,在左右兩方分別找距離它最近的比他大的值,這個可以用單調棧On維護,線段樹加二分Onlog2n維護,分塊On根號n維護,暴力N^2維護都能過

T2

最終復雜度只能是n^2log級別的,可以先二分邊長,之後枚舉最上方的行,算出最下方的行,之後將所有點掃一遍,上下界在這個區間的點進行縱坐標排序,n掃一遍判斷符合要求的最小值更新答案。

T3:這個題目是計算幾何,真的沒看出來,可以做出s/t圖像 將會發現在每個線段交點處可能存在上下擴展的情況可能成為最小值,近一步討論可以發現只有在上下凸殼上的交點才有可能在向上向下的擴展中求最大值,所以求凸殼,可以在排序後Nlogn求出,之後枚舉點進行計算就能過。不過我覺得我那個推論應該沒問題,只是應該把求最值的算法改成三分而不是二分

代碼:

T1:

#include<cstdio>
#include
<algorithm> #include<cmath> #include<iostream> #define MAXN 52521 using namespace std; int hi[MAXN]; int ver[MAXN]; int kuai[MAXN]; int belong[MAXN]; int get_[MAXN]; int n; int kuaishu,biaozhun; int read() { int nm_ = 0; char c = getchar(); while(c > 9 || c <
0)c = getchar(); while(c >= 0 && c <= 9) { nm_ *= 10; nm_ += c - 0; c = getchar(); } return nm_; } int find(int be,int ed,int k) { if(be > ed)return 0; for(int i = ed; i >= (belong[ed] - 1) * biaozhun + 1;i--) if(hi[i] > k) return i; for(int i = belong[ed] - 1;i >= 1;i--) { if(kuai[i] > k) { for(int j = i * biaozhun;j >= (i - 1) * biaozhun + 1;j--) if(hi[j] > k) return j; } } return 0; } int rfind(int be,int ed,int k) { if(be > ed)return 0; for(int i = be;i <= min(belong[be] * biaozhun,n);i++) if(hi[i] > k) return i; for(int i = belong[be] + 1;i <= belong[ed];i++) { if(kuai[i] > k) for(int j = (i - 1) * biaozhun + 1;j <= min(n,i * biaozhun);j++) if(hi[j] > k) return j; } return 0; } int main() { freopen("treasure.in","r",stdin);freopen("treasure.out","w",stdout); n = read(); biaozhun = sqrt(n); for(int i = 1;i <= n;i++) { belong[i] = ((i - 1) / biaozhun) + 1; hi[i] = read(); ver[i] = read(); kuai[belong[i]] = max(kuai[belong[i]],hi[i]); } for(int i = 1;i <= n;i++) { int q = find(1,i - 1,hi[i]);get_[q] += ver[i]; q = rfind(i + 1,n,hi[i]);get_[q] += ver[i]; } int ans = 0; for(int i = 1;i <= n;i++) { ans = max(ans,get_[i]); } cout << ans; fclose(stdin);fclose(stdout); return 0; }

T2:

#include<cstdio>
#include<algorithm>
#include<iostream>
#define MAXN 2001
using namespace std;
struct Note{
    int x;
    int y;
}note[MAXN]; 
int stack_[MAXN];
int top; 
int p,n;
int ans = 0x7ffffff;

int read()
{
    int nm = 0;
    char c = getchar();
    while(c > 9|| c < 0)c = getchar();
    while(c >= 0 && c <= 9)
    {
        nm *= 10;
        nm += c - 0;
        c = getchar();
    }
    return nm; 
}

bool cmp(Note a, Note b)
{
    return a.x < b.x;
}


bool cango(int be,int ed,int k)
{
    top = 0;
    for(int i = 1;i <= n;i++)
    {
        if(note[i].x >= be && note[i].x <= ed)
            stack_[++top] = note[i].y;
    }
    sort(stack_ + 1,stack_ + top + 1);
    if(top < p)return false; 
    for(int i = p;i <= top;i++)
    {
        ans = min(ans,max(k,stack_[i] - stack_[i - p + 1] + 1));
        if(stack_[i] - stack_[i - p + 1] <= k)return true; 
    }
    return false;
}

bool check_(int k)
{
    for(int i = 1;i <= n;i++)
    {
        int be = note[i].x;
        int ed = be + k - 1;
        if(be > 10000)return false;
        if(cango(be,ed,k))return true;
    }
    return false;
} 

int main()
{
    freopen("square.in","r",stdin);freopen("square.out","w",stdout);
    p = read();n = read();
    for(int i = 1;i <= n;i ++)
    {
        note[i].x = read();
        note[i].y = read();
    }
    sort(note + 1,note + n + 1,cmp);
    
    int l = 1,r = 10000;
    while(l + 1 < r)
    {
        int mid = (l + r) >> 1;
        if(check_(mid))r = mid;
        else l = mid; 
    }
    check_(l);check_(r);
    cout <<ans; 
    return 0;
}

T3:

/*(60分)*/
#include<cstdio>
#include<iostream>
#define MAXN 123456 
using namespace std;
double v[MAXN];
double t[MAXN];
double s[MAXN]; 
int n;

double min(double a,double b)
{
    return a < b ? a : b;
}
double max(double a,double b)
{
    return a > b ? a : b;
}

double check_(double tm)
{
    double minn = 2099999999.0;
    double maxx = 0;
    for(int i = 1;i <= n;i++)
    {
        double op = s[i] + v[i] * tm;// s = vt
        minn = min(minn,op);
        maxx = max(maxx,op); 
    }
    return maxx - minn;
}


int main()
{
    freopen("chase.in","r",stdin);freopen("chase.out","w",stdout);
    scanf("%d",&n);
    double T = 0;
    for(int i = 1;i <= n;i++)
    {
        scanf("%lf%lf",&t[i],&v[i]);
        T = max(T,t[i]);
    }
    for(int i = 1;i <= n;i++)
    {
        s[i] = (T - t[i]) * v[i];//計時開始的時候已經跑過的路程 
    }
    double l = 1,r = 987654321;
    while(r - l > 0.00001)
    {
        double zz = (r - l) / 3.0;
        double ln = l + zz;
        double rn = r - zz;
        double lnow = check_(ln);
        double rnow = check_(rn);
        if(lnow > rnow)l = ln;
        else r = rn;    
    }
    printf("%.2lf",check_(l));
    fclose(stdin);fclose(stdout);
    return 0;
}

清北學堂國慶day4解題報告