2019.10.25 csp-s模擬測試87 反思總結

一次很是神奇的考試,考完試之後看着T2的0pts忽然笑死我本身node

太智障了這什麼神奇的題意理解錯誤23333ios

 

T1一眼分類討論,兩眼二分,以爲分類討論有點玄學可是出題人八成不會卡【何】,而後本着對二分的恐懼打了玄學ide

關於T2,我沒了 豹笑 我沒想到一隻鳥可能被打兩槍你敢信ui

T3?今天有T3?spa

 

T1:code

正解是顯而易見的二分。然而我比較懶,又常常在二分上炸掉【寫得比較醜】,並且第一眼其實並非二分。blog

若是k最後小於1,那麼相對於原來1個單位時間的移動來講,確定這種上下移動的步數越多越好。先dfs一次,跑出從起點到終點上下移動步數最多的最短路,而後計算出對應的k。若是這個k解出來大於1,就再跑一次使左右移動步數最多的最短路,再次解出k。這樣能夠保證選取這個k的同時,跑的必定是最短路。排序

其實老是隱約不太放心,感受可能有鍋XD然而最後A了隊列

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
using namespace std;
int n,m,sx,sy,tx,ty;
int a[110][110],vis[110][110];
int h[4]={0,-1,0,1};
int l[4]={-1,0,1,0};
double s;
struct node{
    int x,y,tmp,dis;
    bool operator < (const node a) const {  
        return tmp < a.tmp;
    }  
};
priority_queue<pair<int,node> >q;
node dfs1(){
    node u;
    u.x=sx,u.y=sy,u.tmp=0;
    q.push(make_pair(0,u));
    while(!q.empty()){
        while(q.size()&&vis[q.top().second.x][q.top().second.y])q.pop();
        if(!q.size())break;
        int d=-q.top().first;
        node x=q.top().second;
        q.pop();
        vis[x.x][x.y]=1;
        if(x.x==tx&&x.y==ty){
            x.dis=d;
            return x;
        }
        for(int i=0;i<4;i++){
            node y=x;
            y.x+=h[i],y.y+=l[i];
            if(y.x>0&&y.x<=n&&y.y>0&&y.y<=m&&!a[y.x][y.y]){
                if(i==1||i==3)y.tmp++;
                q.push(make_pair(-(d+1),y));
            }
        }
    }
}
node dfs2(){
    node u;
    u.x=sx,u.y=sy,u.tmp=0;
    while(!q.empty())q.pop();
    memset(vis,0,sizeof(vis));
    q.push(make_pair(0,u));
    while(!q.empty()){
        while(q.size()&&vis[q.top().second.x][q.top().second.y])q.pop();
        if(!q.size())break;
        int d=-q.top().first;
        node x=q.top().second;
        q.pop();
        vis[x.x][x.y]=1;
        if(x.x==tx&&x.y==ty){
            x.dis=d;
            return x;
        }
        for(int i=0;i<4;i++){
            node y=x;
            y.x+=h[i],y.y+=l[i];
            if(y.x>0&&y.x<=n&&y.y>0&&y.y<=m&&!a[y.x][y.y]){
                if(i==0||i==2)y.tmp++;
                q.push(make_pair(-(d+1),y));
            }
        }
    }
}
int main()
{
    scanf("%d%d",&n,&m);
    scanf("%d%d%d%d",&sx,&sy,&tx,&ty);
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            scanf("%d",&a[i][j]);
        }
    }
    scanf("%lf",&s);
    node b=dfs1();
    double k=(1.0*s-1.0*b.dis+1.0*b.tmp)/(1.0*b.tmp);//tmp上下,dis-tmp左右 
    if(k<1)printf("%.3lf",k);
    else{
        b=dfs2();
        k=(1.0*s-1.0*b.tmp)/(1.0*(b.dis-b.tmp));//tmp左右,dis-tmp上下 
        printf("%.3lf",k);
    }
    return 0;
}
View Code

 

T2:string

什麼?一隻鳥有可能被打兩次……?是你R光速換彈仍是我鯤化而爲鵬……?

咳咳,不是否是,其實真的挺智障的,竟然沒想到一隻鳥所佔的區間可能會長於換彈時間…老實說,考試的時候仍是不太認真XD

發現一隻鳥可能被打兩次之後,就要考慮重複的問題。把區間排序之後扔進隊列能夠解決當前時間的區間覆蓋數目。

而後要從0~i-k選出一個去掉重複個數的f[j]進行轉移。選取最大的f值以及對重複個數的修改均可以利用線段樹完成。線段樹以時間爲下標,儲存f[i]-(同時覆蓋i與當前時間的區間個數)。維護方式是,根據前面的隊列,當有新的區間的l覆蓋了當前時間而入隊時,使得l到r這一段區間-1,含義是這一段對於當前時間多了一個重複區間。而一段隊列裏的區間的r小於當前時間出隊時,再把對應的l到r這一段+1,這一個區間再也不重複了。

從0掃到max,max是最大的r。ans即爲最大的(根據當前時間i查詢的線段樹中0->i-k中最大值+當前時間點的區間覆蓋數量【隊列size】)。

要注意各處l或r小於0的區間的處理。

#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
int n,k,top=1,ans,sum,maxx;
struct node{
    int l,r;
    bool operator < (const node x)const{
        return l==x.l?r<x.r:l<x.l;
    }
}a[200010];
priority_queue<pair<int,node> >q;
struct tree{
    int l,r,maxx,tag;
}b[500010*8];
void pushdown(int p){
    if(b[p].tag){
        b[p*2].tag+=b[p].tag;
        b[p*2].maxx+=b[p].tag;
        b[p*2+1].tag+=b[p].tag;
        b[p*2+1].maxx+=b[p].tag;
        b[p].tag=0;
    }
}
void pushup(int p){
    b[p].maxx=max(b[p*2].maxx,b[p*2+1].maxx);
}
void build(int p,int l,int r){
    b[p].l=l,b[p].r=r;
    b[p].maxx=b[p].tag=0;
    if(l==r)return;
    int mid=(l+r)/2;
    build(p*2,l,mid);
    build(p*2+1,mid+1,r);
}
void change(int p,int l,int r,int y){
    if(l<=b[p].l&&b[p].r<=r){
        b[p].maxx+=y;
        b[p].tag+=y;
        return;
    }
    pushdown(p);
    int mid=(b[p].l+b[p].r)/2;
    if(l<=mid)change(p*2,l,r,y);
    if(r>mid)change(p*2+1,l,r,y);
    pushup(p);
}
void update(int p,int l,int r,int y){
    if(l<=b[p].l&&b[p].r<=r){
        b[p].maxx=y;
        b[p].tag=0;
        return;
    }
    pushdown(p);
    int mid=(b[p].l+b[p].r)/2;
    if(l<=mid)update(p*2,l,r,y);
    if(r>mid)update(p*2+1,l,r,y);
    pushup(p);
}
int ask(int p,int l,int r){
    if(l<=b[p].l&&b[p].r<=r){
        return b[p].maxx;
    }
    pushdown(p);
    int mid=(b[p].l+b[p].r)/2;
    int val=0;
    if(l<=mid)val=max(val,ask(p*2,l,r));
    if(r>mid)val=max(val,ask(p*2+1,l,r));
    pushup(p);
    return val;
}
int main(){
    scanf("%d%d",&n,&k);
    for(int i=1;i<=n;i++){
        scanf("%d%d",&a[i].l,&a[i].r);
        maxx=max(maxx,a[i].r);
    }
    sort(a+1,a+n+1);
    build(1,0,maxx);
    for(int i=0;i<=maxx;i++){
        while(a[top].l<=i&&top<=n){
            if(a[top].r<0){
                top++;
                continue;
            }
            q.push(make_pair(-a[top].r,a[top]));
            change(1,max(0,a[top].l),a[top].r,-1);
            top++;
        }
        while(q.top().second.r<i&&q.size()){
            change(1,max(0,q.top().second.l),q.top().second.r,+1);
            q.pop();
        }
        if(i>=k)sum=ask(1,0,i-k);
        update(1,i,i,sum);
        ans=max(ans,sum+(int)q.size());
    }
    printf("%d\n",ans);
    return 0;
} 
View Code

蠢出必定程度了…線段樹寫錯+隊列沒考慮l的入隊順序不必定是r的出隊順序因而沒寫優先隊列…改了挺長時間的

 

T3:

咕 咕咕咕 咕咕咕咕【飛了】

 

今天發現各處瀰漫着稍許頹廢的氣息

多是 秋天到了吧【何】

相關文章
相關標籤/搜索