CSP模拟8

垫底了……垫底了……感觉这场真的好摆。垫底是必然的。一堆良心暴力都没打。
一眼望过去都可做但挂了又被一堆pj题薄纱。

排序是个好东西。它的作用已经不是一开始排个大小那么简单了,让区间有序可以便利很多操作。比如T2双指针不用担心 x 乱序的问题。T4的离线更简单的思考问题。有序的东西真的会方便思考,不会就排序。一些很常见的技巧见过但想不到。
似乎人人都喜欢有序的东西。


A. Coprime 2

卡了根号的,没有关系我根号写挂了……
考虑枚举因数然后筛掉跟埃筛差不多。

要重新拿一个数组存a数组的出现,重新拿一个筛数,要不会多筛掉答案。


B.Dist Max 2
读错题,寄了,虽然只有一行的题干。

一眼二分答案。先对坐标按照x为第一关键字排序。维护双指针在区间[x,x+mid] 判断y是否合法。

Code
int check(int mid){
    int mx=-1e9+7,mn=1e9+7;

    for(int i=1,j=1;i<=n;i++){
        while(j<i&&a[i].x-a[j].x>=mid){
            mx=max(mx,a[j].y);
            mn=min(mn,a[j].y);
            j++;
        }

        if(mx-mid>=a[i].y)
            return 1;
        if(mn+mid<=a[i].y)
            return 1;
    }
    return 0;
}

考试时忽略了下标的对应关系,做法一眼假。
重新思考check时忘记了可以排序,认为数据太乱不知所措(其实就是菜)。

xuany老师把线段树 x下处放上了 y 二分判断。
这也是处理二维数点的好方法。


Count Multiset

跟昨天差不多的DP,但还是没写出来。
依旧是前面可以加 0 可以整体加 1 $ f _{i,j} = f _{i-1,j} + f _{i,j-i}$
但由于又个数限制所以不可以一直加1 所以 $ f _{i-1,j} $ 并不好控制。
开一个辅助数组 $ g _{i,j} 表示其没有0和为j的个数。g _{i,j} = f _{i,j-i} $ 那么 $ f _{i,j} = \Sigma _{k<=m} g[k][j] +f _{i,j-i} $ 可以前缀和优化。

Code
    scanf("%lld%lld",&n,&m);

    for(int i=0;i<=m;i++)
        dp1[i][0]=1;

    for(int i=1;i<=n;i++){
        for(int j=1;j<=n;j++){
            if(j>=i){
                dp1[i][j]=dp1[i][j-i]%mod;
                dp2[i][j]=dp1[i][j-i]%mod;
            }

            sum[i][j]=(sum[i-1][j]%mod+dp2[i][j]%mod)%mod;
            dp1[i][j]=(dp1[i][j]%mod+(sum[i-1][j]%mod-sum[max(0,i-m-1)][j]%mod+mod)%mod+mod)%mod;
        }
    }

    for(int i=1;i<=n;i++){
        printf("%lld\n",dp2[i][n]%mod);
    }


Julia the snail
只想到了离线扫描线,但没打。感觉这场真的好摆。
暴力是暴力跳绳。考虑优化暴力。
对于所有可以到r答案小与r的都附上r.好像是经典吉司机线段树。

oj数据不保证 r 唯一。oj开到1e6卡掉了分块。(不卡也不会)

Code
inline int max(int a,int b){
    return a>b?a:b;
}

struct Ques{
    int y,id;
};
vector <Ques> q[N];

int n,m,Q;
int ans[N];
int L[N];

struct Tree{
    int mx,lastmx;
}t[N<<2];

inline void push_up(int k){
    if(t[lc].mx==t[rc].mx){
        t[k].mx=t[lc].mx;
        t[k].lastmx=max(t[lc].lastmx,t[rc].lastmx);
    }else if(t[lc].mx>t[rc].mx){
        t[k].mx=t[lc].mx;
        t[k].lastmx=max(t[lc].lastmx,t[rc].mx);
    }else{
        t[k].mx=t[rc].mx;
        t[k].lastmx=max(t[lc].mx,t[rc].lastmx);
    }
}

inline void push_down(int k){
    if(t[lc].mx<t[k].mx&&t[lc].mx>t[k].lastmx)
        t[lc].mx=t[k].mx;
    if(t[rc].mx<t[k].mx&&t[rc].mx>t[k].lastmx)
        t[rc].mx=t[k].mx;
}

void build(int k,int l,int r){
    if(l==r){
        t[k].mx=l;
        return ;
    }

    int mid=(l+r)>>1;
    build(lc,l,mid);
    build(rc,mid+1,r);

    push_up(k);
}

void update(int k,int l,int r,int L,int R,int val){
    if(L<=l&&r<=R){
        if(R>t[k].mx)
            return;
        if(t[k].mx>=R&&t[k].lastmx<R){
            t[k].mx=val;
        }else{
            int mid=(l+r)>>1;
            push_down(k);

            update(lc,l,mid,L,R,val);
            update(rc,mid+1,r,L,R,val);

            push_up(k);
        }

        return ;
    }

    int mid=(l+r)>>1;
    push_down(k);
    
    if(L<=mid)
        update(lc,l,mid,L,R,val);
    if(R>mid)
        update(rc,mid+1,r,L,R,val);
    
    push_up(k);
}

int query(int k,int l,int r,int pos){
    if(l==r){
        return t[k].mx;
    }

    int mid=(l+r)>>1;

    push_down(k);

    if(pos<=mid)
        return query(lc,l,mid,pos);
    else
        return query(rc,mid+1,r,pos);
}

int main(){
    n=read(),m=read();

    for(int i=1;i<=m;i++){
        int x=read(),y=read();
        L[y]=x;
    }

    Q=read();

    for(int i=1;i<=Q;i++){
        int x=read(),y=read();
        q[y].push_back((Ques){x,i});
    }

    build(1,1,n);
    
    for(int i=1;i<=n;i++){
        if(L[i]){
            update(1,1,n,1,L[i],i);
        }

        if(!q[i].size())
            continue;
        for(int k=0;k<q[i].size();k++){
            ans[q[i][k].id]=query(1,1,n,q[i][k].y);
        }
    }

    for(int i=1;i<=Q;i++){
        write(ans[i]);
    }

    return 0;
}

posted @ 2023-07-29 09:48  Ysz_y  阅读(17)  评论(0)    收藏  举报