2025多校冲刺省选模拟赛9

2025多校冲刺省选模拟赛9

T1 A. 鸬鹚 20pts

  • 部分分

    • 30pts
      • 顺次迭代,并查集优化不明显。

      • 判断矩形相交时在特判掉包含后可以直接代入四个角进行判断。

        点击查看代码
        struct node
        {
            int x1,x2,y1,y2;
            node operator + (const node &another) const
            {
                return (node){min(x1,another.x1),
                            max(x2,another.x2),
                            min(y1,another.y1),
                            max(y2,another.y2)};
            }
        }f[2][100010];
        bool cmp(node a,node b)
        {
            if(a.x1!=b.x1)  return a.x1<b.x1;
            if(a.x2!=b.x2)  return a.x2<b.x2;
            if(a.y1!=b.y1)  return a.y1<b.y1;
            return a.y2<b.y2;
        }
        struct DSU
        {
            int fa[100010];
            void init(int n)
            {
                for(int i=1;i<=n;i++)  fa[i]=i;
            }
            int find(int x)
            {
                return fa[x]==x?x:fa[x]=find(fa[x]);
            }
            void merge(int x,int y,int op)
            {
                x=find(x);  y=find(y);
                if(x!=y)
                {
                    fa[y]=x;
                    f[op][x]=f[op][x]+f[op][y];
                }
            }
        }D;
        int cnt[2];
        bool check(int x1,int y1,int x2,int y2,int _x1,int _y1,int _x2,int _y2)
        {
            if(x1<_x1)
            {
                swap(x1,_x1);  swap(y1,_y1);  swap(x2,_x2);  swap(y2,_y2);
            }
            return (x1<_x2&&((_y1<=y1&&y1<_y2)||(_y1<y2&&y2<=_y2)||(y1<=_y1&&_y2<=y2)));
        }
        int main()
        {
        #define Isaac
        #ifdef Isaac
            freopen("cormorant.in","r",stdin);
            freopen("cormorant.out","w",stdout);
        #endif
            int n,flag,i,j,op=0;
            cin>>n;  cnt[op]=n;
            for(i=1;i<=n;i++)  cin>>f[op][i].x1>>f[op][i].x2>>f[op][i].y1>>f[op][i].y2;
            for(flag=1;flag==1;op^=1)
            {
                flag=cnt[op^1]=0;
                D.init(cnt[op]);
                for(i=1;i<=cnt[op];i++)
                {
                    int x=D.find(i);
                    for(j=i+1;j<=cnt[op];j++)
                    {
                        if(check(f[op][x].x1,f[op][x].y1,f[op][x].x2,f[op][x].y2,
                                f[op][j].x1,f[op][j].y1,f[op][j].x2,f[op][j].y2)==true)
                        {
                            flag=1;
                            D.merge(x,j,op);
                        }	
                    }
                }
                for(i=1;i<=cnt[op];i++)
                {
                    if(D.fa[i]==i)
                    {
                        cnt[op^1]++;
                        f[op^1][cnt[op^1]]=f[op][i];
                    }
                }
            }
            op^=1;
            sort(f[op]+1,f[op]+1+cnt[op],cmp);
            cout<<cnt[op]<<endl;
            for(i=1;i<=cnt[op];i++)  cout<<f[op][i].x1<<" "<<f[op][i].x2<<" "<<f[op][i].y1<<" "<<f[op][i].y2<<endl;
            return 0;
        }
        
  • 正解

    • 瓶颈在于判断合并时难以钦定一个次数较少的顺序。即使是类似 Boruvka 的过程也无法处理。
    • [x1,x2] 为线段树的下标,不断将矩形扔到根链的节点上。插入的时候先将能合并的合并掉(删除原来的矩形),在末尾添加本次加入的矩形。
    • 暴力遍历整个链表不可接受,需要进一步优化:先将矩形按照 y2 排序使得在不相交时直接退出;为减少重复合并次数影响后续便利,对矩形进行当前弧优化使得只合并一次。
    • 具体实现时可以将 x1,y1 先进行 +1 简化判断矩形相交的限制条件。
    点击查看代码
    struct node
    {
        int x1,x2,y1,y2;
        node operator + (const node &another) const
        {
            return (node){min(x1,another.x1),
                        max(x2,another.x2),
                        min(y1,another.y1),
                        max(y2,another.y2)};
        }
    }a[100010];
    int d[200010],vis[200010];
    bool cmp1(node a,node b)
    {
        return a.y2<b.y2;
    }
    bool cmp2(node a,node b)
    {
        if(a.x1!=b.x1)  return a.x1<b.x1;
        if(a.x2!=b.x2)  return a.x2<b.x2;
        if(a.y1!=b.y1)  return a.y1<b.y1;
        return a.y2<b.y2;
    }
    bool check(int x,int y)
    {
        return a[x].y2>=a[y].y1&&a[y].y2>=a[x].y1;
    }
    struct SMT
    {
        struct SegmentTree
        {
            vector<int>all,part;
        }tree[800010];
        #define lson(rt) (rt<<1)
        #define rson(rt) (rt<<1|1)
        void update(int rt,int l,int r,int x,int y,int id)
        {
            tree[rt].part.push_back(id);
            if(x<=l&&r<=y)
            {
                tree[rt].all.push_back(id);
                return;
            }
            int mid=(l+r)/2;
            if(x<=mid)  update(lson(rt),l,mid,x,y,id);
            if(y>mid)  update(rson(rt),mid+1,r,x,y,id);
        }
        bool del(vector<int>&v,int id)
        {
            int flag=0;
            while(v.empty()==0&&(vis[v.back()]==1||check(v.back(),id)==true))
            {
                if(vis[v.back()]==0)
                {
                    vis[v.back()]=1;
                    a[id]=a[id]+a[v.back()];
                    flag=1;
                }
                v.pop_back();
            }
            return flag;
        }
        bool query(int rt,int l,int r,int x,int y,int id)
        {
            if(del(tree[rt].all,id)==true)  return true;
            if(x<=l&&r<=y)  return del(tree[rt].part,id);
            int mid=(l+r)/2;
            if(y<=mid)  return query(lson(rt),l,mid,x,y,id);
            if(x>mid)  return query(rson(rt),mid+1,r,x,y,id);
            return query(lson(rt),l,mid,x,y,id)|query(rson(rt),mid+1,r,x,y,id);
        }
    }T;
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("cormorant.in","r",stdin);
        freopen("cormorant.out","w",stdout);
    #endif
        int n,m=0,i;
        cin>>n;
        for(i=1;i<=n;i++)  
        {
            cin>>a[i].x1>>a[i].x2>>a[i].y1>>a[i].y2;
            a[i].x1++;  a[i].y1++;
            d[0]++;  d[d[0]]=a[i].x1;
            d[0]++;  d[d[0]]=a[i].x2;
        }
        sort(a+1,a+1+n,cmp1);
        sort(d+1,d+1+d[0]);  d[0]=unique(d+1,d+1+d[0])-(d+1);
        for(i=1;i<=n;i++)
        {
            a[i].x1=lower_bound(d+1,d+1+d[0],a[i].x1)-d;
            a[i].x2=lower_bound(d+1,d+1+d[0],a[i].x2)-d;
            while(T.query(1,1,d[0],a[i].x1,a[i].x2,i)==true);
            T.update(1,1,d[0],a[i].x1,a[i].x2,i);
        }
        for(i=1;i<=n;i++)
        {
            if(vis[i]==0)  
            {
                m++;
                a[m]=a[i];
            }
        }
        sort(a+1,a+1+m,cmp2);
        cout<<m<<endl;
        for(i=1;i<=m;i++)  cout<<d[a[i].x1]-1<<" "<<d[a[i].x2]<<" "<<a[i].y1-1<<" "<<a[i].y2<<endl;
        return 0;
    }
    

T2 B. 雪雀 0pts

  • 部分分

    • 30pts :暴力跑 Dijkstra
    点击查看代码
    const ll p=1000000007,dx[4]={0,0,1,-1},dy[4]={-1,1,0,0};
    ll a[4][200010],dis[4][200010],vis[4][200010],m;
    struct quality
    {
        ll x,y,dis;
        bool operator < (const quality &another) const
        {
            return dis>another.dis;
        }
    };
    void dijkstra(ll sx,ll sy)
    {
        for(ll i=1;i<=3;i++)
        {
            for(ll j=1;j<=m;j++)
            {
                dis[i][j]=0x3f3f3f3f3f3f3f3f;
                vis[i][j]=0;
            }
        }
        priority_queue<quality>q;
        dis[sx][sy]=a[sx][sy];
        q.push((quality){sx,sy,dis[sx][sy]});
        while(q.empty()==0)
        {
            ll x=q.top().x,y=q.top().y;
            q.pop();
            if(vis[x][y]==0)
            {
                vis[x][y]=1;
                for(ll i=0;i<=3;i++)
                {
                    ll nx=x+dx[i],ny=y+dy[i];
                    if(1<=nx&&nx<=3&&1<=ny&&ny<=m&&dis[nx][ny]>dis[x][y]+a[nx][ny])
                    {
                        dis[nx][ny]=dis[x][y]+a[nx][ny];
                        q.push((quality){nx,ny,dis[nx][ny]});
                    }
                }
            }
        }
    }
    ll solve(ll sx,ll sy)
    {
        ll ans=0;
        dijkstra(sx,sy);
        for(ll i=1;i<=3;i++)
        {
            for(ll j=1;j<=m;j++)  
            {
                if(i==sx&&j==sy)  continue;
                ans=(ans+dis[i][j]%p)%p;
            }
        }
        return ans;
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("snowfinch.in","r",stdin);
        freopen("snowfinch.out","w",stdout);
    #endif
        ll ans=0,i,j;
        scanf("%lld",&m);
        for(i=1;i<=3;i++)
        {
            for(j=1;j<=m;j++)  scanf("%lld",&a[i][j]);
        }
        for(i=1;i<=3;i++)
        {
            for(j=1;j<=m;j++)  ans=(ans+solve(i,j))%p;
        }
        printf("%lld\n",ans);
        return 0;
    }
    
  • 正解

    • 先考虑怎么快速处理多源最短路。
    • fi,gi 表示仅考虑 [1,i]/[i,n]a1,ia3,i 的最短路,转移方程为 {fi=min(fi1,a2,i)+a1,i+a3,igi=min(gi+1,a2,i)+a1,i+a3,i
    • 此时如果我们能够顺次(从右到左或从左到右)得到若干个点到某一个汇点的距离,则分讨三个转移而来的方向即可得到所在位置的最短路。
    • 接着考虑分治。设当前分治区间为 [l,r] ,则统计出 u[l,mid],v[mid+1,r] 的最短路 dis(u,v)
    • 显然 u,v 之间的最短路形如 u(k,mid)(k,mid+1)v,k{0,1,2} 。由上面的转移容易得到左右两边每个点到 (k,mid),(k,mid+1) 的最短路。
    • ak 表示 u(k,mid) 的最短路, bk 表示 v(k,mid+1) 的最短路。则有 min(a1+b1,a2+b2,a3+b3) 即为所求。
    • 假设 a1+b1 被计入答案则有 a1+b1a2+b2,a3+b3 ,移项分别得到 {a1a2b2b1a1a3b3b1 ,树状数组维护扫描线即可。具体地,将 u 看做修改,将 v 看做查询。
    • 注意因最短路相等而导致的算重问题。
    点击查看代码
    const ll p=1000000007;
    ll a[4][200010],f[200010],g[200010],L[4][4][200010],R[4][4][200010],d[600010],n,ans=0;
    struct node
    {
        ll x,y,val,op;
        bool operator < (const node &another) const
        {
            return (x==another.x)?(op<another.op):(x<another.x);
        }
    };
    vector<node>q;
    struct BIT
    {
        ll c[2][600010];
        void clear()
        {
            for(ll i=1;i<=d[0];i++)  c[0][i]=c[1][i]=0;
        }
        ll lowbit(ll x)
        {
            return (x&(-x));
        }
        void add(ll n,ll x,ll val1,ll val2)
        {
            for(ll i=x;i<=n;i+=lowbit(i))
            {
                c[0][i]=(c[0][i]+val1)%p;
                c[1][i]=(c[1][i]+val2)%p;
            }
        }
        ll getsum(ll x,ll val)
        {
            ll sum1=0,sum2=0;
            for(ll i=x;i>=1;i-=lowbit(i))
            {
                sum1=(sum1+c[0][i])%p;
                sum2=(sum2+c[1][i])%p;
            }
            return (sum1+sum2*val%p)%p;
        }
    }T;
    void dp(ll l,ll r,ll mid)
    {
        L[1][1][mid]=a[1][mid];  L[1][2][mid]=a[1][mid]+a[2][mid];  L[1][3][mid]=min(f[mid],g[mid]);
        L[2][1][mid]=a[1][mid]+a[2][mid];  L[2][2][mid]=a[2][mid];  L[2][3][mid]=a[2][mid]+a[3][mid];
        L[3][1][mid]=min(f[mid],g[mid]);  L[3][2][mid]=a[2][mid]+a[3][mid];  L[3][3][mid]=a[3][mid];
        for(ll op=1;op<=3;op++)
        {
            for(ll i=mid-1;i>=l;i--)
            {
                L[op][1][i]=min({L[op][1][i+1]+a[1][i],L[op][2][i+1]+a[2][i]+a[1][i],L[op][3][i+1]+f[i]}); // 从 (1,i) 到 (op,mid)
                L[op][3][i]=min({L[op][1][i+1]+f[i],L[op][2][i+1]+a[2][i]+a[3][i],L[op][3][i+1]+a[3][i]});
                L[op][2][i]=min({L[op][1][i]+a[2][i],L[op][2][i+1]+a[2][i],L[op][3][i]+a[2][i]});
            }
        }
        mid++;
        R[1][1][mid]=a[1][mid];  R[1][2][mid]=a[1][mid]+a[2][mid];  R[1][3][mid]=min(f[mid],g[mid]);
        R[2][1][mid]=a[1][mid]+a[2][mid];  R[2][2][mid]=a[2][mid];  R[2][3][mid]=a[2][mid]+a[3][mid];
        R[3][1][mid]=min(f[mid],g[mid]);  R[3][2][mid]=a[2][mid]+a[3][mid];  R[3][3][mid]=a[3][mid];
        for(ll op=1;op<=3;op++)
        {
            for(ll i=mid+1;i<=r;i++)
            {
                R[op][1][i]=min({R[op][1][i-1]+a[1][i],R[op][2][i-1]+a[2][i]+a[1][i],R[op][3][i-1]+g[i]});
                R[op][3][i]=min({R[op][1][i-1]+g[i],R[op][2][i-1]+a[2][i]+a[3][i],R[op][3][i-1]+a[3][i]});
                R[op][2][i]=min({R[op][1][i]+a[2][i],R[op][2][i-1]+a[2][i],R[op][3][i]+a[2][i]});
            }
        }
    }
    void work()
    {
        T.clear();  sort(q.begin(),q.end());
        d[0]=0;
        for(ll i=0;i<q.size();i++)  d[++d[0]]=q[i].y;
        sort(d+1,d+1+d[0]);  d[0]=unique(d+1,d+1+d[0])-(d+1);
        for(ll i=0;i<q.size();i++)
        {
            q[i].y=lower_bound(d+1,d+1+d[0],q[i].y)-d;
            if(q[i].op==0)  T.add(d[0],q[i].y,q[i].val%p,1);
            else  ans=(ans+T.getsum(q[i].y,q[i].val%p))%p;
        }
    }
    void solve(ll l,ll r)
    {
        if(l==r)
        {
            ans=(ans+a[1][l]+2*a[2][l]+a[3][l]+min(f[l],g[l]))%p;
            return;
        }
        ll mid=(l+r)/2;
        solve(l,mid);  solve(mid+1,r);
        dp(l,r,mid);
        for(ll z=1;z<=3;z++)
        {
            q.clear();
            ll x=((z==1)?2:1),y=((z==3)?2:3);
            for(ll op=1;op<=3;op++)
            {
                for(ll i=l;i<=mid;i++)  q.push_back((node){L[z][op][i]-L[x][op][i]+(z!=1),L[z][op][i]-L[y][op][i]+(z==3),L[z][op][i],0});
                for(ll i=mid+1;i<=r;i++)  q.push_back((node){R[x][op][i]-R[z][op][i],R[y][op][i]-R[z][op][i],R[z][op][i],1});
            }	
            work();
        }
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("snowfinch.in","r",stdin);
        freopen("snowfinch.out","w",stdout);
    #endif
        cin>>n;
        for(ll i=1;i<=3;i++)
        {
            for(ll j=1;j<=n;j++)  cin>>a[i][j];
        }
        f[0]=g[n+1]=0x3f3f3f3f3f3f3f3f;
        for(ll i=1;i<=n;i++)  f[i]=min(f[i-1],a[2][i])+a[1][i]+a[3][i];
        for(ll i=n;i>=1;i--)  g[i]=min(g[i+1],a[2][i])+a[1][i]+a[3][i];
        solve(1,n);
        cout<<ans*2%p<<endl;
        return 0;
    }
    

T3 C. 燕鸥 0pts

  • 正解

    点击查看代码
    ll calc(ll pos,ll n,ll l,ll r)
    {
        ll x=0,h=0;
        while((x+1)*3<=pos-1)  x=(x+1)*3;
        x++;  h=x;
        if(x!=pos)
        {
            h+=(2-(pos-x)%2)*pos+(x-pos)/2;  x=pos;
        }
        while(x+1<=n&&h>=x+1)
        {
            x++;  h-=x;
        }
        if((n-x)>h*2)
        {
            x+=h*2;  h=0;
            while((x+1)*3<=n-1)  x=(x+1)*3;
            x++;  h=x;	
        }
        h+=(n-x)%2*n-(n-x)/2;
        return l<=h&&h<=r;
    }
    ll solve(ll n,ll l,ll r)
    {
        ll ans=calc(n-1,n,l,r)+calc(n,n,l,r),x;
        for(ll i=1;i<=min(n-2,3ll);i++)  ans+=calc(i,n,l,r);
        if(n>=4)
        {	
            x=3;
            while((x+1)*3<n-1)
            {
                ans+=calc(x+3,n,l,r)*(((x+1)*3-x-2)/2-1);
                ans+=calc(x+1,n,l,r)*(((x+1)*3-x-1)/2+1);
                x=(x+1)*3;
                ans+=calc(x,n,l,r)+calc(x-2,n,l,r);
            }
            if((n-1-x)%2==1)
            {
                ans+=calc(x+3,n,l,r)*((n-1-x-2)/2-((x+1)*3-2<n-1));
                ans+=calc(x+1,n,l,r)*((n-1-x-1)/2+1);
                if((x+1)*3-2<n-1)  ans+=calc((x+1)*3-2,n,l,r);
            }
            else
            {
                ans+=calc(n-2,n,l,r);
                if(x+1!=n-2)
                {
                    ans+=calc(x+3,n,l,r)*((n-2-x-2)/2-((x+1)*3-2<n-1));
                    ans+=calc(x+1,n,l,r)*((n-2-x-1)/2+1);
                    if((x+1)*3-2<n-1)  ans+=calc((x+1)*3-2,n,l,r);
                }
            }
        }	
        return ans;
    }
    int main()
    {
    #define Isaac
    #ifdef Isaac
        freopen("tern.in","r",stdin);
        freopen("tern.out","w",stdout);
    #endif
        ll t,n,l,r,i;
        cin>>t;
        for(i=1;i<=t;i++)
        {
            cin>>n>>l>>r;
            cout<<solve(n,l,r)<<endl;
        }
        return 0;
    }
    

总结

  • T1 因常数较大,挂了 10pts
  • T2 忘开 long long 和大量使用 memset 挂了 30pts

后记

  • 教练开场 0.5h 才想起来放下发文件。
  • T2 题面有点误导人了,读了 2h 后才明白问的是什么。
  • T3 题面中问的是具体方案,但只回答了方案数。
posted @   hzoi_Shadow  阅读(90)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· 写一个简单的SQL生成工具
· Manus的开源复刻OpenManus初探
扩大
缩小
点击右上角即可分享
微信分享提示