『模拟赛』暑假集训CSP提高模拟11

Rank

昨天积攒的 rp 生效了!

image

A. Fate

签到题。

次短路计数,感觉做过类似的,不过这里次短路定义为最短路长度 +1,赛时把自环想成环了,原谅我犯唐。

还是用 dijkstra,我们这次开两个 dis 数组存最短路和次短路长度,然后两个 cnt 数组存二者的个数,稍微想想就能想到一共的四种可能:

  • 更新后长度小于最短路长度,那么现将用最短路更新次短路,然后将这条路径置为最短路,数量为更新路径的数量。
  • 长度等于最短路,直接数量 +1。
  • 长度小于次短路,将这条路置为次短路,数量为更新路径的数量。
  • 长度等于次短路,直接数量 +1。
点击查看代码
const int N=2e5+5;
const int mod=1e9+7;
int n,m,st,ed;
int hh[N],to[N<<1],ne[N<<1],w[N<<1],cntt;
ll dis[N][2],yz[N][2],cnt[N][2];
struct rmm
{
    ll d,num,zl;
    bool operator<(const rmm &a)const{return d>a.d;}
};
namespace Wisadel
{
    void Wadd(int u,int v,int va)
    {
        to[++cntt]=v;
        w[cntt]=va;
        ne[cntt]=hh[u];
        hh[u]=cntt;
    }
    void Wdij(int x)
    {
        priority_queue<rmm>q;
        memset(dis,0x3f,sizeof dis);
        dis[x][0]=0,cnt[x][0]=1;
        q.push((rmm){0,x,0});
        while(q.size())
        {
            ll u=q.top().num,zl=q.top().zl;q.pop();
            if(yz[u][zl]) continue;
            yz[u][zl]=1;
            for(int i=hh[u];i!=-1;i=ne[i])
            {
                int v=to[i];
                if(dis[v][0]>dis[u][zl]+w[i])
                {// 最短
                    dis[v][1]=dis[v][0];
                    cnt[v][1]=cnt[v][0];
                    q.push((rmm){dis[v][1],v,1});
                    // 先更新次短
                    dis[v][0]=dis[u][zl]+w[i];
                    cnt[v][0]=cnt[u][zl];
                    q.push((rmm){dis[v][0],v,0});
                }
                else if(dis[v][0]==dis[u][zl]+w[i])
                    cnt[v][0]=(cnt[v][0]+cnt[u][zl])%mod;
                else if(dis[v][1]>dis[u][zl]+w[i])
                {// 次短
                    dis[v][1]=dis[u][zl]+w[i];
                    cnt[v][1]=cnt[u][zl];
                    q.push((rmm){dis[v][1],v,1});
                }
                else if(dis[v][1]==dis[u][zl]+w[i])
                    cnt[v][1]=(cnt[v][1]+cnt[u][zl])%mod;
            }
        }
    }
    short main()
    {
        // freopen("Fate9.in","r",stdin),freopen(".out","w",stdout);
        n=qr,m=qr;st=qr,ed=qr;
        memset(hh,-1,sizeof hh);
        fo(i,1,m)
        {
            int a=qr,b=qr;
            Wadd(a,b,1),Wadd(b,a,1);
        }
        Wdij(st);
        if(dis[ed][0]+1==dis[ed][1])
            printf("%lld\n",cnt[ed][1]);
        else printf("0\n");
        return Ratio;
    }
}
int main(){return Wisadel::main();}

B. EVA

原[ABC274F] Fishing

也挺水的,感觉之前做过这个类型的,这个多处理些细节就好了。

首先挺显然的,最优策略时开始撒网的地点肯定有一条鱼。

发现 n2000,所以考虑枚举左端点的鱼,然后对剩下的鱼求出有贡献的答案范围,复杂度是 O(n2) 的。

有几个注意的点。

首先对于速度相同的两条鱼,显然只看初始位置就好了。

实现上,为了防止精度出现误差,存位置的变量尽量使用 double 类型。

对于两条鱼,有 s=x2x1+t×(v2v1),做出贡献的范围为 s[0,a],那么移个项可得 t[x1x2v2v1,a+x1x2v2v1],这样我们便可以依据时间算出贡献,存储用个 map 就好。

点击查看代码
#include<bits/stdc++.h>

using namespace std;
const int Ratio=0;
const int N=2e4+5;
const double eps=1e-9;

int n,m,ans=-1e9;
struct rmm
{
    int w,x,v;
}fis[N];
map<double,int>mp;

namespace Wisadel
{
    short main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%d%d%d",&fis[i].w,&fis[i].x,&fis[i].v);
        for(int i=1;i<=n;i++)
        {
            mp.clear();
            int w=fis[i].w,x=fis[i].x,v=fis[i].v;
            int now=w;
            for(int j=1;j<=n;j++)
            {
                if(i==j) continue;
                if(fis[j].v==v&&fis[j].x>=x&&fis[j].x<=x+m)
                {// 速度相同的情况
                    now+=fis[j].w;
                    continue;
                }
                double fw1=1.0*(x-fis[j].x)/(fis[j].v-v),fw2=1.0*(m+x-fis[j].x)/(fis[j].v-v);
                if(fw1>fw2) swap(fw1,fw2);
                // 左右边界
                if(fw2>=0)
                {
                    if(fw1<1.0*0) fw1=1.0*0;
                    mp[fw1]+=fis[j].w,mp[fw2+eps]-=fis[j].w;
                    // 右边界 +eps 即为超出答案范围一点点的位置
                }
            }
            int anss=now;
            for(auto [a,b]:mp) now+=b,anss=max(anss,now);
            // 根据边界界定找最优答案
            ans=max(ans,anss);
        }
        printf("%d\n",ans);
        return Ratio;
    }
}
int main(){return Wisadel::main();}

C. 嘉然登场

原[ARC148E] ≥ K

一眼计数题,赛时想推 k=1 结论,推了近二十分钟发现假了,重复不算,然后摆。

感觉赛时 AK 大佬的题解是目前看过最易懂的题解,搬了。

D. Clannad

感觉暴力都想假了,只推出链的做法。

找到链头和链尾,映射一个顺序到原来的城镇编号上。

对于序列,我们直接找到两点映射间最大的坐标差 +1 即为答案的值。

那么查询,容易想到线段树,我们只需要建立一个存映射后编号的最大值和最小值的线段树,每次查找这两个值,就能得出答案了。

点击查看部分分代码

已经读入了部分数据。

namespace Wistask3
{
    int num[N],tot,st,ed;
    int minn[N<<2],maxx[N<<2];
    void Wdfs(int u,int fa)
    {
        num[u]=++tot;
        if(u==ed) return;
        for(int i=hh[u];i!=-1;i=ne[i])
        {
            int v=to[i];
            if(v!=fa) Wdfs(v,u);
        }
    }
    #define ls (rt<<1)
    #define rs (rt<<1|1)
    #define mid ((l+r)>>1)
    void Wpushup(int rt)
    {
        minn[rt]=min(minn[ls],minn[rs]);
        maxx[rt]=max(maxx[ls],maxx[rs]);
    }
    void Wbuild(int rt,int l,int r)
    {
        if(l==r)
        {
            minn[rt]=maxx[rt]=num[a[l]];
            return;
        }
        Wbuild(ls,l,mid),Wbuild(rs,mid+1,r);
        Wpushup(rt);
    }
    int Wqmax(int rt,int l,int r,int x,int y)
    {
        if(x<=l&&r<=y) return maxx[rt];
        int res=-1e9;
        if(x<=mid) res=max(res,Wqmax(ls,l,mid,x,y));
        if(y>mid) res=max(res,Wqmax(rs,mid+1,r,x,y));
        return res;
    }
    int Wqmin(int rt,int l,int r,int x,int y)
    {
        if(x<=l&&r<=y) return minn[rt];
        int res=1e9;
        if(x<=mid) res=min(res,Wqmin(ls,l,mid,x,y));
        if(y>mid) res=min(res,Wqmin(rs,mid+1,r,x,y));
        return res;
    }
    short main()
    {
        // cout<<"+====="<<endl;
        fo(i,1,n)
        {
            if(in[i]==1&&!st) st=i;
            else if(in[i]==1&&!ed) ed=i;
            if(st&&ed) break;
        }
        Wdfs(st,0);
        Wbuild(1,1,m);
        while(q--)
        {
            int a=qr,b=qr;
            int sma=Wqmin(1,1,m,a,b),big=Wqmax(1,1,m,a,b);
            printf("%d\n",big-sma+1);
        }
        return Ratio;
    }
}

今天发挥出正常实力了,果然早起是有用的。

不过部分分还是拿的不全,比赛要专心拼啊。


完结撒花~

rp 这么有用,继续点踩吧(雾

posted @   Ratio_Y  阅读(100)  评论(7编辑  收藏  举报
相关博文:
阅读排行:
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探
点击右上角即可分享
微信分享提示