20260927 模拟赛 总结

前言

真的是 s 组模拟赛嘛……感觉是 j+/s- 的难度喵 qwq。

T3/T4 的难度没怎么上去,不过 T1 还是有一定难度的。(如果你是认认真真推的话

T4 涉黄……OvO

好难……好难……没做出来 T4 这辈子有了……对吧……

基本信息

  • 时间:2026 年 9 月 27 日
  • 时长:4h
  • 题目数量:4 题
  • 得分:100+100+100+40=340pts
  • 排名:rk3

赛时情况

T1

  • 估分:100pts
  • 实际:100pts
  • 时间段:约 8:05~8:40
  • 耗时:约 35min

赛时做法:推了很多神秘的东西,还尝试递推,最后发现极简式子,一测大样例全过了,应该稳了。

戳这里看赛时代码
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
using namespace std;
LL n;
LD Ans;
LL read(){
    LL su=0,pp=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
    return su*pp;
}

int main(){
    freopen("socks.in","r",stdin);
    freopen("socks.out","w",stdout);
    n=read();
    Ans=1.0*n/(2*n-1);
    printf("%.10Lf\n",Ans);
    return 0;
}
/*



*/ 

T2

  • 估分:100pts
  • 实际:100pts
  • 时间段:约 8:40~9:05
  • 耗时:约 25min

赛时做法:一眼想出做法,需要用到 ST。我最开始觉得还好,但比赛还剩 30min 的时候发现可能存在 MLE 现象,于是卡了卡空间,删掉了一些冗余的数组防止浪费空间。

闲话:我认为 T2<<<<<T1。

戳这里看赛时代码
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
using namespace std;
const int N = 5005;
const int M = 2005;
const int INF = 2e9+712;
int n,m,k,a[N],b[N],Ans;
int s[N][M][12],lg2[N];
int read(){
    int su=0,pp=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
    return su*pp;
}
namespace io { 
const int L = (1 << 21) + 1; 
char ibuf[L], *iS, *iT, obuf[L], *oS = obuf, *oT = obuf + L - 1, c, st[55]; 
int f, tp; 
#define gc() (iS==iT?(iT=(iS=ibuf)+fread(ibuf,1,L,stdin),(iS==iT?EOF:*iS++)):*iS++) 
inline void gi(int& x) { //get 
for (f = 1, c = gc(); c < '0' || c > '9'; c = gc()) 
if (c == '-') f = -1; 
for (x = 0; c <= '9' && c >= '0'; c = gc()) x = x * 10 + (c & 15); 
x *= f; 
} 
};  
// namespace io 
using io::gi; 
int ask(int x,int l,int r){
    if(r<l)return INF;
    int k=lg2[r-l+1];
    return min(s[x][l][k],s[x][r-(1<<k)+1][k]);
}
int main(){
    freopen("sleep.in","r",stdin);
    freopen("sleep.out","w",stdout);
    gi(n),gi(m),gi(k);
    //n=read(),m=read(),k=read();
    for(int i=1;i<=n;i++)
        //a[i]=read(),b[i]=read();
        gi(a[i]),gi(b[i]);
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            //c[i][j]=read();
            gi(s[i][j][0]);
    for(int i=2;i<=m;i++)lg2[i]=lg2[i/2]+1;
    for(int x=1;x<=n;x++){
        for(int j=1;(1<<j)<=m;j++)
            for(int i=1;i+(1<<j)-1<=m;i++)
                s[x][i][j]=min(s[x][i][j-1],s[x][i+(1<<j-1)][j-1]);
    }
    Ans=INF;
    for(int u=1;u<=m;u++){
        int x=u,y=u+k-1;
        if(y<=m){
            //正常区间
            int res=0;
            bool ok=0;//如果 ok=1 表示无解 
            for(int i=1;i<=n;i++){//枚举每个人 
                //a+b-1<x a<x-b+1 a<=x-b
                int tmp=ask(i,1,x-b[i]);
                //a>y a>=y+1
                tmp=min(tmp,ask(i,y+1,min(m,m+x-b[i])));
                if(tmp>=INF){ok=1;break;}
                res+=tmp;
            }
            if(!ok)Ans=min(Ans,res);
        }
        else{
            //只有一个区间 欸那不是更好做吗!
            int res=0;
            bool ok=0;//ok=1 表示无解 
            y-=m;//恢复正常 
            for(int i=1;i<=n;i++){
                //那么 a 只能在 [y+1,x-1-b+1] 中取
                int tmp=ask(i,y+1,x-b[i]);
                if(tmp>=INF){ok=1;break;}
                res+=tmp; 
            }
            if(!ok)Ans=min(Ans,res);
        }
    }
    cout<<Ans<<"\n";
    return 0;
}

T3

  • 估分:100pts
  • 实际:100pts
  • 时间段:约 9:10~11:30(和 T4 一起做的)
  • 耗时:不知道

赛时做法:最开始想到了对每台公交站建虚点,然后处理路径上的向上取整情况,时间复杂度大约是 \(O(nk \log n)\),60pts。后来发现可以在虚点的时候直接将其 \(dis\) 数组向上取整就能做出满分,中途调了一下。

戳这里看赛时代码
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
using namespace std;
const int N = 3e5+5;
const LL INF = 2e15+521712;
struct node{LL u,step;};
bool operator < (const node &A , const node &B){
    return A.step>B.step;
}
LL n,m,k,r,Q,val[N],dis[N];
bool vis[N];
vector<pLL> e[N];
priority_queue<node> q;
LL read(){
    LL su=0,pp=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
    return su*pp;
}
LL dij(int S,int T){
    e[T].pb({n+k+1,0});
    for(int i=1;i<=n+k+1;i++)dis[i]=INF,vis[i]=0;
    while(!q.empty())q.pop();
    dis[S]=0;q.push({S,0});
    while(!q.empty()){
        int u=q.top().u;
        LL ds=q.top().step;
        q.pop();
        if(vis[u])continue;
        vis[u]=1;
        //cout<<u<<"!\n";
        if(u>n)dis[u]=(dis[u]+r-1)/r*r;
        //cout<<"?\n";
        for(int i=0;i<e[u].size();i++){
            LL v=e[u][i].fr,w=e[u][i].se;
            if(ds+w<dis[v]){
                //if(v==6)cout<<u<<"to "<<dis[u]<<"+"<<w<<"!!\n";
                dis[v]=dis[u]+w,q.push({v,dis[v]});
            }
        }
    }
    //for(int i=1;i<=n+k+1;i++)cout<<dis[i]<<" ";cout<<"\n";
    e[T].pop_back();
    return dis[n+k+1];
}
int main(){
    freopen("route.in","r",stdin);
    freopen("route.out","w",stdout);
    n=read(),m=read(),k=read();
    r=read(),Q=read();
    for(int i=1;i<=m;i++){
        int x=read(),y=read();
        LL w=read();
        e[x].pb({y,w}),e[y].pb({x,w});
    }
    for(int i=1;i<=k;i++){
        int cnt=read();val[i]=read();
        while(cnt--){
            int x=read();
            e[n+i].pb({x,val[i]*r});
            e[x].pb({n+i,0});
        }
    }
    while(Q--){
        int x=read(),y=read();
        LL res=dij(x,y)/r;
        cout<<res<<"\n";
    }
    return 0;
}
/*

6 5 2 3 1
1 2 4
2 3 10
3 4 4
4 5 10
5 6 4
2 1 2 3
2 1 4 5
1 6


*/

T4

  • 估分:40pts
  • 实际:40pts
  • 时间段:约 9:40~11:30(和 T3 一起做的)
  • 耗时:不知道

赛时做法:最开始看成最长上升子序列了,写了一个树状数组优化 dp,结果样例没过,重读题发现是极长上升子序列。重新构思 dp,写了一份 dp,后续一直在想正解但实在没有弄出来,因为一直想着维护一个单调栈,没发现每次枚举一遍的时间复杂度也是可以接受的。

戳这里看赛时代码
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
using namespace std;
const int N = 6005;
const LL MOD = 998244353;
LL n,a[N],Ls[N],cnt,mx[N];
LL dp[N];
LL now,Ans;
LL read(){
    LL su=0,pp=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
    return su*pp;
}
int main(){
    freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++)
        a[i]=read(),Ls[++cnt]=a[i];
    sort(Ls+1,Ls+cnt+1);
    cnt=unique(Ls+1,Ls+cnt+1)-Ls-1;
    for(int i=1;i<=n;i++)
        a[i]=lower_bound(Ls+1,Ls+cnt+1,a[i])-Ls;
    for(int i=n;i>=1;i--)
        mx[i]=max(mx[i+1],a[i]);
    dp[0]=1;
    for(int i=1;i<=n;i++){
        int lst=0;
        for(int j=i-1;j>=0;j--){
            if(a[j]>=a[i])continue;
            //if(i==7)cout<<j<<"?"<<(a[j]>=lst)*dp[j]<<"!!\n";
            if(a[j]>=lst)dp[i]=(dp[i]+dp[j])%MOD,lst=a[j];
        } 
        //cout<<dp[i]<<" ";
        if(mx[i+1]<=a[i])Ans=(Ans+dp[i])%MOD;
    }
    //cout<<"\n";
    cout<<Ans<<"\n";
    return 0;
}
/*
10
4 1 7 3 9 2 6 10 5 8
1 1 2 1 3 1 2 2 2 4


*/

赛后补题:通过询问gpt得知发现可以一步步递推到答案,然后发现还可以以 \(a_i\) 为下标维护最大的 \(i\)。然后中午的时候写了线段树优化 dp,过了。

戳这里看赛后代码
#include<bits/stdc++.h>
#define LL long long
#define UInt unsigned int
#define ULL unsigned long long
#define LD long double
#define pii pair<int,int>
#define pLL pair<LL,LL>
#define pDD pair<LD,LD>
#define fr first
#define se second
#define pb push_back
#define isr insert
#define _i128 __int128
using namespace std;
const int N = 2e5+5;
const LL INF = 2e9+712;
const LL MOD = 998244353;
int n,a[N],tr[N<<2];
LL dp[N],Ans;
int read(){
    int su=0,pp=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')pp=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){su=su*10+ch-'0';ch=getchar();}
    return su*pp;
}
int ls(int u){return (u<<1);}
int rs(int u){return (u<<1|1);}
void push_up(int u){
    tr[u]=max(tr[ls(u)],tr[rs(u)]);
    return;
}
void change(int u,int l,int r,int pos,int k){
    if(l==r&&l==pos){tr[u]=k;return;}
    int mid=(l+r)>>1;
    if(pos<=mid)change(ls(u),l,mid,pos,k);
    else change(rs(u),mid+1,r,pos,k);
    push_up(u);return;
}
int ask(int u,int l,int r,int L,int R){
    if(r<L||R<l)return 0;
    if(L<=l&&r<=R)return tr[u];
    int mid=(l+r)>>1;
    return max(ask(ls(u),l,mid,L,R),ask(rs(u),mid+1,r,L,R));
}
int main(){
    freopen("seq.in","r",stdin);
    freopen("seq.out","w",stdout);
    n=read();
    for(int i=1;i<=n;i++)a[i]=read();
    memset(tr,-1,sizeof(tr));
    int mn=INF,mx=0;
    for(int i=1;i<=n;i++){
        if(a[i]<mn)dp[i]=1;
        mn=min(mn,a[i]);
        for(int x=1;x<a[i];){
            int pos=ask(1,1,n,x,a[i]-1);
            if(pos<=0)break;
            dp[i]=(dp[i]+dp[pos])%MOD;
            x=a[pos]+1;
        }
        change(1,1,n,a[i],i);
    }
    Ans=0;
    for(int i=n;i>=1;mx=max(mx,a[i]),i--)
        if(a[i]>mx)Ans=(Ans+dp[i])%MOD;
    cout<<Ans<<"\n";
    return 0;
}

整体反思

T1 没有最开始就通过大样例思考,导致浪费了较多时间;T2 倒是做的还挺快;T3 没有最开始就想出正解;T4 没有发现一步步递推的均摊时间复杂度是正确的,因此浪费了较多时间。

哦。不。

闲话

好难……

T4 seq 真的不是 色情 的意思吗。我是不相信的。

感觉第一场没出出难度,后面要有福咯。

没拿到 400 这辈子有了……有的时候真的觉得自己很该死你知道吗——!

T2 没判 -1 还 A 了谁的一辈子哦哦哦哦哦哦哦哦哦↗↘↗↘↗↘↗

csp rp++

posted @ 2026-09-27 15:27  嘎嘎喵  阅读(31)  评论(2)    收藏  举报