1. 程式人生 > >10.1綜合強化刷題 Day4

10.1綜合強化刷題 Day4

正方形 ans 是否 fabs math limit 不能 har 速度

財富(treasure)

Time Limit:1000ms Memory Limit:128MB

題目描述

LYK有n個小夥伴。每個小夥伴有一個身高hi。

這個遊戲是這樣的,LYK生活的環境是以身高為美的環境,因此在這裏的每個人都羨慕比自己身高高的人,而每個人都有一個屬性ai表示它對身高的羨慕值。

這n個小夥伴站成一列,我們用hi來表示它的身高,用ai來表示它的財富。

每個人向它的兩邊望去,在左邊找到一個最近的比自己高的人,然後將ai朵玫瑰給那個人,在右邊也找到一個最近的比自己高的人,再將ai朵玫瑰給那個人。當然如果沒有比自己身高高的人就不需要贈送別人玫瑰了。也就是說一個人會給0,1,2個人玫瑰(這取決於兩邊是否有比自己高的人)。

每個人都會得到若幹朵玫瑰(可能是0朵),LYK想知道得了最多的玫瑰的那個人得了多少玫瑰。(然後嫁給他>3<)

輸入格式(treasure.in)

第一行一個數n表示有n個人。

接下來n行,每行兩個數hi,ai。

輸出格式(treasure.out)

一個數表示答案。

輸入樣例

3

4 7

3 5

6 10

輸出樣例

12

樣例解釋

第一個人會收到5朵玫瑰,第二個沒人送他玫瑰,第三個人會收到12朵玫瑰。

數據範圍

對於50%的數據n<=1000,hi<=1000000000。

對於另外20%的數據n<=50000,hi<=10。

對於100%的數據1<=n<=50000,1<=hi<=1000000000。1<=ai<=10000。

一個簡單的單調棧

我們跑兩遍單調棧,先正著跑一遍(處理出每一個人給右邊第一個比他高的),在倒著跑一遍(處理出每個人把花給他左邊第一個比他高的)

技術分享
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1000010
using namespace std;
int n,ans,sum[N],q[N],h[N],a[N],stack[N]; int read() { int x=0,f=1; char ch=getchar(); while(ch<0||ch>9) ch=getchar(); while(ch>=0&&ch<=9) x=x*10+ch-0,ch=getchar(); return x*f; } int main() { // freopen("treasure.in","r",stdin); // freopen("treasure.out","w",stdout); n=read(); for(int i=1;i<=n;i++) h[i]=read(),a[i]=read(); for(int top=0,i=1;i<=n;i++) { while(top&&stack[top]<=h[i]) top--; sum[q[top]]+=a[i]; stack[++top]=h[i];q[top]=i; } for(int top=0,i=n;i>=1;i--) { while(top&&stack[top]<=h[i]) top--; sum[q[top]]+=a[i]; stack[++top]=h[i];q[top]=i; } for(int i=1;i<=n;i++) ans=max(ans,sum[i]); printf("%d",ans); return 0; }
AC代碼

正方形(square)

Time Limit:1000ms Memory Limit:128MB

題目描述

在一個10000*10000的二維平面上,有n顆糖果。

LYK喜歡吃糖果!並且它給自己立了規定,一定要吃其中的至少C顆糖果!

事與願違,LYK只被允許圈出一個正方形,它只能吃在正方形裏面的糖果。並且它需要支付正方形邊長的價錢。

LYK為了滿足自己的求食欲,它不得不花錢來圈一個正方形,但它想花的錢盡可能少,你能幫幫它嗎?

輸入格式(square.in)

第一行兩個數C和n。

接下來n行,每行兩個數xi,yi表示糖果的坐標。

輸出格式(square.out)

一個數表示答案。

輸入樣例

3 4

1 2

2 1

4 1

5 2

輸出樣例

4

樣例解釋

選擇左上角在(1,1),右下角在(4,4)的正方形,邊長為4。

數據範圍

對於30%的數據n<=10。

對於50%的數據n<=50。

對於80%的數據n<=300。

對於100%的數據n<=1000。1<=xi,yi<=10000。

當我看到這個題的時候就在想,這不就是個求最小的矩形,並且使這個矩形中的糖果的個數是否大於了c。然後蒟蒻本質暴露了出來,我企圖用一個前綴和統計每個矩形內的糖果個數,然後在暴力枚舉矩形邊長和右下斷點,判斷是否合理,結果數組不是開大了就是開小了,直接崩潰

如果我們打算要用上面的做法的話我們需要離散化一下裏面的點,不然最後一個點可能出現在10000,10000上,這樣我們用一個前綴和處理的話會崩潰。

我們來看一下正解,數據範圍在1000以內,能承受的時間復雜度為n^2logn的。

我們可以試著二分一下,二分矩形的邊長,然後我們再試著枚舉左邊界,通過左邊界我們就可以知道右邊界,同樣通過右邊界我們也可以知道左邊界,然後我們再在通過左右邊界來判斷裏面的糖果數是否足夠,當然我們的上下也是有邊界的,我們在當前左右所加的這個矩形裏,如果糖果數不夠c那麽直接返回false,反之,我們在來判斷一下在這個區間裏每個糖果的y坐標排序,然後將這個糖果的y與他的前c個糖果的y比較,如果小於等於mid的話,說明在這樣的長度裏我們可以找到c個糖果。

技術分享
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<iostream>
#include<algorithm>
#define N 1010
using namespace std;
int c,n,L,R,mid,ans,cnt,tmp[N];
int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<0||ch>9){if(ch==-)f=-1; ch=getchar();}
    while(ch>=0&&ch<=9) x=x*10+ch-0,ch=getchar();
    return x*f;
}
struct Node
{
    int x,y;
}a[N];
int cmp(Node a,Node b)
{
    return a.x<b.x;
}
int work(int l,int r)
{
    if(r-l+1<c) return false;
    cnt=0;
    for(int i=l;i<=r;i++)
     tmp[++cnt]=a[i].y;
    sort(tmp+1,tmp+1+cnt);
    for(int i=c;i<=cnt;i++)
     if(tmp[i]-tmp[i-c+1]<=mid) return true;
    return false; 
}
int pd(int x)
{
    int l=1;
    for(int r=1;r<=n;r++)
    {
        if(a[r].x-a[l].x>x)
        {
            if(work(l,r-1)) return true;
            while(a[r].x-a[l].x>x) l++;
        }
    }
    if(work(l,n)) return true;
    return false; 
}
int main()
{
    c=read(),n=read();
    for(int i=1;i<=n;i++) a[i].x=read(),a[i].y=read();
    sort(a+1,a+1+n,cmp);
    L=1,R=10000,mid=(L+R)/2;
    while(L<=R)
    {
        if(pd(mid)) ans=mid+1,R=mid-1,mid=(L+R)/2;
        else L=mid+1,mid=(L+R)/2; 
    }
    printf("%d",ans);
    return 0;
}

AC代碼
AC代碼

追逐(chase)

Time Limit:1000ms Memory Limit:128MB

題目描述

這次,LYK以一個上帝視角在看豹子賽跑。

在一條無線長的跑道上,有n只豹子站在原點。第i只豹子將在第ti個時刻開始奔跑,它的速度是vi/時刻。

因此在不同的時刻,這n只豹子可能在不同的位置,並且它們兩兩之間的距離也將發生變化。

LYK覺得眼光八方太累了,因此它想找這麽一個時刻,使得最遠的兩只豹子的距離盡可能近,當然這不能是第0時刻或者第0.01時刻。它想知道的是最遲出發的豹子出發的那一刻開始,離得最遠的兩只豹子在距離最小的時候這個距離是多少。

當然這個時刻不僅僅可能發生在整數時刻,也就是說可能在1.2345時刻這個距離最小。

輸入格式(chase.in)

第一行一個數n。

接下來n行,每行兩個數分別是ti和vi。

輸出格式(chase.out)

輸出一個數表示答案,你只需保留小數點後兩位有效數字就可以了。

輸入樣例

3

1 4

2 5

3 7

輸出樣例

0.33

樣例解釋

在第5+2/3這個時刻,第一只豹子在18+2/3這個位置,第二只豹子在18+1/3這個位置,第三只豹子在18+2/3這個位置,最遠的兩只豹子相距1/3的距離,因此答案是0.33。

數據範圍

對於20%的數據n=2。

對於20%的數據n=3

對於60%的數據n<=100。

對於80%的數據n<=1000。

對於100%的數據n<=100000,1<=vi,ti<=100000。

看到這個題的部分分,然後很開心,前兩個點可以特判的、、

前4個點,也可以手算的,就是有點麻煩,所以蒟蒻在考場中並沒有寫、、、

技術分享
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define N 1100
using namespace std;
int n,t[N],v[N];
double ans;
int read() 
{
    int x=0,f=1; char ch=getchar();
    while(ch<0||ch>9) ch=getchar();
    while(ch>=0&&ch<=9) x=x*10+ch-0,ch=getchar();
    return x*f;
}
int work1()
{
    if(t[1]<t[2]&&v[1]>=v[2]) ans=v[1]*(t[2]-t[1]);
    if(t[1]<t[2]&&v[1]<v[2]) ans=0;
    if(t[2]<t[1]&&v[2]>=v[1]) ans=v[2]*(t[1]-t[2]);
    if(t[2]<t[1]&&v[2]<v[1]) ans=0;
}
int work2()
{
    ans=0.33;
}
int main()
{
    freopen("chase.in","r",stdin);
    freopen("chase.out","w",stdout);    
    n=read(); 
    for(int i=1;i<=n;i++)
     t[i]=read(),v[i]=read();
    if(n==2) work1();
    else work2();
    printf("%.2lf",ans);
    return 0;
}
20分的特判

然後我們來看正解

什麽?!竟然是解析幾何?!啊啊啊,這題沒法做了!

棄療吧、、

技術分享
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>

using namespace std;
const long double INF=(long double)1000000000*10;
long double L,R,mid,ans,hh[100005];
int r,rr,i,n,MAX,X,Y,cnt,vv[100005],vv2[100005];
struct node2 {int t; long double l;} s[200005],S[200005];
struct node {int t,v;} t[100005];
int cmp(node i,node j) {return i.v<j.v || i.v==j.v && i.t>j.t;}
struct Node {long double x;int y,z;} p[200005];
int CMP(Node i,Node j) {return i.x<j.x;}
long double work(int x,long double y) {return (long double)t[x].v*y-hh[x];}
int main()
{
    freopen("chase.in","r",stdin);
    freopen("chase.out","w",stdout);
    while (1)
    {
        scanf("%d",&n);
       // if (n==0) return 0;
        MAX=0;
        for (i=1; i<=n; i++)
        {
            scanf("%d%d",&t[i].t,&t[i].v);
            MAX=max(MAX,t[i].t);
        }
        sort(t+1,t+n+1,cmp); int MIN=t[n].t;
        for (i=n-1; i>=2; i--)
        {
            if (t[i].t>MIN) vv[i]=1; else
            MIN=t[i].t,vv[i]=0;
        }
        for (i=1; i<=n; i++) hh[i]=(long double)t[i].t*t[i].v;
        r=1; s[1].l=MAX; s[1].t=1; s[2].l=INF; vv[n]=0;
        for (i=2; i<=n; i++)
        if (!vv[i])
        {
            while (r && work(i,s[r].l)>=work(s[r].t,s[r].l)) r--;
            if (!r) {r=1; s[1].l=MAX; s[1].t=i; continue;}
            L=s[r].l; R=s[r+1].l; mid=(L+R)/2.0;
            for (int I=1; I<=80; I++)
            {
                if (work(i,mid)>=work(s[r].t,mid)) {R=mid; mid=(L+R)/2.0;} else {L=mid; mid=(L+R)/2.0;}
            }
            s[++r].l=mid; s[r].t=i; s[r+1].l=INF;
        }
        rr=1; S[1].l=MAX; S[2].l=INF; S[1].t=n;
        MIN=t[1].t;
        for (i=2; i<n; i++)
          if (t[i].t<MIN) vv2[i]=1; else
            MIN=t[i].t,vv2[i]=0;
        for (i=n-1; i>=1; i--)
        if (!vv2[i])
        {
            while (rr && work(i,S[rr].l)<=work(S[rr].t,S[rr].l)) rr--;
            if (!rr) {rr=1; S[1].l=MAX; S[1].t=i; continue;}
            L=S[rr].l; R=S[rr+1].l; mid=(L+R)/2.0;
            for (int I=1; I<=80; I++)
            {
                if (work(i,mid)<=work(S[rr].t,mid)) {R=mid; mid=(L+R)/2.0;} else {L=mid; mid=(L+R)/2.0;}
            }
            S[++rr].l=mid; S[rr].t=i; S[rr+1].l=INF;
        }
        cnt=0;
        for (i=1; i<=r; i++) {p[++cnt].x=s[i].l; p[cnt].y=1; p[cnt].z=s[i].t;}
        for (i=1; i<=rr; i++) {p[++cnt].x=S[i].l; p[cnt].y=0; p[cnt].z=S[i].t;}
        sort(p+1,p+cnt+1,CMP); X=Y=0; ans=INF;
        for (i=1; i<=cnt; i++)
        {
            if (p[i].y==1) X=p[i].z; else Y=p[i].z;
          //  printf("%.5f\n",(double)p[i].x);
            if (X && Y) ans=min(ans,work(X,p[i].x)-work(Y,p[i].x));
        }
        printf("%.2f\n",fabs((double)ans));
        return 0;
    }
}
標程

10.1綜合強化刷題 Day4