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++

浙公网安备 33010602011771号