『模拟赛』CSP-S模拟2
Rank
非常好数据,使我成为 Rank1(雾
数据换源后的
狂流——齐秦
北风在吹着清冷的街道
街灯在拉开长长的影子
走过的路 想过的事
仿佛越来越远越来越长
越来越多越难以抛开
多少平淡日子以来的夜晚
你曾是我渴望拥有的企盼
太多分手的记忆
仿佛越来越远越来越长
越来越多越难以抛开
没有人能挽回时间的狂流
没有人能誓言相许永不分离
是我的错
是你错过 喔...
没有人能挽回时间的狂流
没有人能了解聚散之间的定义
太多遗憾 太多伤感
留在心中 像一道狂流
没有人能挽回时间的狂流
没有人能誓言相许永不分离
是我的错
是你错过 喔...
没有人能挽回时间的狂流
没有人能了解聚散之间的定义
太多遗憾 太多伤感
留在心中 像一道狂流
多少平淡日子以来的夜晚
你曾是我渴望拥有的企盼
太多分手的记忆
仿佛越来越远越来越长
越难以抛开
没有人
没有人
没人了解
没人了解
没有人
没有人
没有人
没有人
北风在吹着冰冷的街道
Upd on 9.8 9:00 :更新了 T3 正解
A. 不相邻集合
签。
用 set 维护的,不仅跑得慢讲的时候还被 hack 了。
考虑正解,并查集维护,我们将当前状态下的序列中连续的数合并在一起,设全部集合为
点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(register int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
char ch=getchar();lx x=0,f=1;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
#undef lx
#define qr qr()
#define fi first
#define se second
const int Ratio=0;
const int N=3e5+5;
const int mod=1e9+7;
const int inf=1e9;
int n,maxn,ans;
int a[N],fx[N<<1],siz[N<<1];
bool yz[N<<1];
namespace Wisadel
{
int Wfind(int x)
{
if(x==fx[x]) return x;
return fx[x]=Wfind(fx[x]);
}
short main()
{
// freopen(".in","r",stdin),freopen(".out","w",stdout);
n=qr;
fo(i,1,n) a[i]=qr;
fo(i,1,500000) fx[i]=i,siz[i]=1;
fo(i,1,n)
{
if(!yz[a[i]])
{
yz[a[i]]=1;
ans++;
if(yz[a[i]-1])
{
int _=Wfind(a[i]),__=Wfind(a[i]-1);
if(_!=__)
{
fx[_]=__;
ans-=(siz[__]+1)/2+(siz[_]+1)/2;
siz[__]+=siz[_];
ans+=(siz[__]+1)/2;
}
}
if(yz[a[i]+1])
{
int _=Wfind(a[i]),__=Wfind(a[i]+1);
if(_!=__)
{
fx[_]=__;
ans-=(siz[__]+1)/2+(siz[_]+1)/2;
siz[__]+=siz[_];
ans+=(siz[__]+1)/2;
}
}
}
printf("%d ",ans);
}
return Ratio;
}
}
int main(){return Wisadel::main();}
B. 线段树
算是签,赛时思路跟正解压根不沾边,只有 20pts。
正解是记搜。一个显然的结论:长度相同的区间的子树标号和是有共性的,即若当前区间的编号为
点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(register int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
char ch=getchar();lx x=0,f=1;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
#undef lx
#define qr qr()
#define fi first
#define se second
const int Ratio=0;
const int N=3e5+5;
const int mod=1e9+7;
const int inf=1e9;
ll n,x,y;
unordered_map<ll,ll>k,b;
namespace Wisadel
{
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
ll Wqk(ll len)
{
if(k.find(len)!=k.end()) return k[len];
int mi=(len+1)>>1;
return k[len]=(2*Wqk(mi)+2*Wqk(len-mi)+1)%mod;
}
ll Wqb(ll len)
{
if(b.find(len)!=b.end()) return b[len];
int mi=(len+1)>>1;
return b[len]=(Wqb(mi)+Wqb(len-mi)+Wqk(len-mi))%mod;
}
ll Wq(ll rt,ll l,ll r,ll x,ll y)
{
if(x<=l&&r<=y) return (rt%mod*Wqk(r-l+1)%mod+Wqb(r-l+1))%mod;
ll res=0;
if(x<=mid) res=Wq(ls,l,mid,x,y);
if(y>mid) res=(res+Wq(rs,mid+1,r,x,y))%mod;
return res;
}
short main()
{
// freopen(".in","r",stdin),freopen(".out","w",stdout);
int T=qr;
k[1]=1,b[1]=0;
while(T--)
{
n=qr,x=qr,y=qr;
printf("%lld\n",Wq(1,1,n,x,y));
}
return Ratio;
}
}
int main(){return Wisadel::main();}
C. 魔法师
神秘题,数据更神秘。
由于赛时被 T2 卡了太久,一眼看出这题不太可做,于是打了
考虑正解。我们发现带一个
学习了 GGrun 用 multiset 模拟开四棵线段树的逃课做法正解。插入时因为
不过代价是时间空间不够优秀,但是拼接 50pts 暴力可以拿到目前能看到的最优解 5854ms。
点击查看代码
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(register int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
char ch=getchar();lx x=0,f=1;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
#undef lx
#define qr qr()
#define fi first
#define se second
const int Ratio=0;
const int N=1e6+2,B=25e4;
const int mod=1e9+7;
const int inf=1e9;
int q,T,ans;
namespace Wisadel
{
int sum[N][2][2],anss[N];
multiset<int> s[N][2][2];
multiset<int>::iterator it;
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
void Wpushup(int rt)
{
sum[rt][0][0]=min(sum[ls][0][0],sum[rs][0][0]);
sum[rt][0][1]=min(sum[ls][0][1],sum[rs][0][1]);
sum[rt][1][0]=min(sum[ls][1][0],sum[rs][1][0]);
sum[rt][1][1]=min(sum[ls][1][1],sum[rs][1][1]);
anss[rt]=min(min(anss[ls],anss[rs]),min(sum[ls][0][1]+sum[rs][1][1],sum[ls][1][0]+sum[rs][0][0]));
}
void Wupd(int rt,int l,int r,int x,int va,int vb,int op)
{
if(l==r)
{
if(!s[l][0][0].size()) s[l][0][0].insert(1e8),s[l][0][1].insert(1e8),s[l][1][0].insert(1e8),s[l][1][1].insert(1e8);
if(op<0)
{
it=s[l][-op-1][0].lower_bound(va);
if(*it==va) s[l][-op-1][0].erase(it);
it=s[l][-op-1][1].lower_bound(vb);
if(*it==vb) s[l][-op-1][1].erase(it);
}
else s[l][op-1][0].insert(va),s[l][op-1][1].insert(vb);
sum[rt][0][0]=*s[l][0][0].begin(),sum[rt][0][1]=*s[l][0][1].begin(),
sum[rt][1][0]=*s[l][1][0].begin(),sum[rt][1][1]=*s[l][1][1].begin();
anss[rt]=min(sum[rt][0][0]+sum[rt][1][0],sum[rt][0][1]+sum[rt][1][1]);
return;
}
if(x<=mid) Wupd(ls,l,mid,x,va,vb,op);
else Wupd(rs,mid+1,r,x,va,vb,op);
Wpushup(rt);
}
short main()
{
// freopen(".in","r",stdin),freopen(".out","w",stdout);
q=qr,T=qr;
memset(sum,0x3f,sizeof sum);
memset(anss,0x3f,sizeof anss);
fo(i,1,q)
{
int op=qr,tt=qr,aa=qr,bb=qr;
if(T) aa^=ans,bb^=ans;
if(op==1)
{
int u=tt?bb-aa:aa-bb;
Wupd(1,1,5e5,u+B,aa,bb,tt+1);
ans=anss[1]>1e6?0:anss[1];
printf("%d\n",ans);
}
else
{
int u=tt?bb-aa:aa-bb;
Wupd(1,1,5e5,u+B,aa,bb,-tt-1);
ans=anss[1]>1e6?0:anss[1];
printf("%d\n",ans);
}
}
return Ratio;
}
}
int main(){return Wisadel::main();}
D. 园艺
一眼可做,再一眼不可做,再再一眼可做。
根据样例得出一个假结论:最优解在整个过程非边界处最多拐一次。然后 5min 写出了式子,10min 打出代码。过一会发现暴力
设
设
过了之后尝试证明了一下结论,发现如果存在:
那么会出现拐两次比拐一次优的情况。但是一眼左边一小点右边一大坨,本能告诉我结论是正确的的,然后水水的数据也是这样的,于是过了。
下午 int_R 送来一组 hack 数据:
5 3
100000 10 100 1000000
又研究了一下,发现如果满足:
即可卡掉,看着很复杂,其实手造还是很容易卡掉的。
错误的满分代码(真的很短)
#include<bits/stdc++.h>
#define fo(x,y,z) for(register int (x)=(y);(x)<=(z);(x)++)
#define fu(x,y,z) for(register int (x)=(y);(x)>=(z);(x)--)
using namespace std;
typedef long long ll;
#define lx ll
inline lx qr()
{
char ch=getchar();lx x=0,f=1;
for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
for(;ch>='0'&&ch<='9';ch=getchar()) x=(x<<3)+(x<<1)+(ch^48);
return x*f;
}
#undef lx
#define qr qr()
#define fi first
#define se second
const int Ratio=0;
const int N=2e6+5;
const int mod=1e9+7;
const int inf=1e9;
int n,k;
ll d[N];
ll ans9223372036854775807,dis[N],sum[N];
namespace Wisadel
{
short main()
{
// freopen("cut2.in","r",stdin),freopen(".out","w",stdout);
n=qr,k=qr;
fo(i,1,n-1) d[i]=qr;
fu(i,k-1,1) dis[i]=dis[i+1]+d[i],sum[i]=sum[i+1]+dis[i];
fo(i,k+1,n) dis[i]=dis[i-1]+d[i-1],sum[i]=sum[i-1]+dis[i];
fu(i,k-1,1) ans=min(ans,sum[i]+sum[n]+(n-k)*2*dis[i]+sum[1]-sum[i]+2*(dis[i]+dis[n])*(i-1));
fo(i,k+1,n) ans=min(ans,sum[i]+sum[1]+(k-1)*2*dis[i]+sum[n]-sum[i]+2*(dis[i]+dis[1])*(n-i));
printf("%lld\n",ans);
return Ratio;
}
}
int main(){return Wisadel::main();}
末
Rank 1拿得挺意外的。本来卡 T2 1.5h 觉得自己跟昨天一样又寄寄了,结果神秘数据直接给我错解全放过了,挺牛的。
那么也反映一个问题,数据强的话又能打多少分呢?所以能过的题不抓住还是挺伤的,比如 T2。
T4 说实话开始猜结论时预期就拿个 50pts 左右,过了大样例给我震惊了,一时间以为把正解按出来了,最后倒计时结束时看到两个绿勾还是很高兴的。
就把这次当做一次激励吧,激励我继续冲击 Rank1 的助推剂,也希望能在这最后纯粹的 OI 时光里留下点什么拼搏的回忆。
Upd on 数据换源后:T3 起码该拿的拿到了,虽然是 Rank2,但起码知道了自己没挂分不是吗?
还有 %%% GGrun。
完结撒花~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探