『模拟赛』暑假集训CSP提高模拟22
Rank
非常好重测,使我 Rank--
A. 法阵
出题人注:原题 3100,张口放 T1
一眼高难度题,于是果断开始暴力打表,但我的打表程序十分暴力,跑
打表就不用放了吧,等我咕咕正解。
B. 连通块
同[yLCPC2024] F. PANDORA PARADOXXX
真正的 T1。
赛时由于 T1 的搞心态以及极冷的室内环境,让我几乎没有办法去想暴力以外的东西。考虑对于每次询问,对询问的该点进行 bfs,删边的话只需要在建边的时候加个序号记一下就行,可以过 50pts;然后对于链的情况,我直接用线段树维护每个区段所属的连通块序号,以及每个联通块的左右边界,实现了
正解是倒过来做,删边操作变成建边操作,每次建边相当于一次树上启发式合并,维护树上直径信息就行了。
点击查看代码
求 LCA 用的倍增,常数较大,酌情参考。
#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=2e5+5;
const int mod=998244353;
int n,m;
int hh[N],to[N<<1],ne[N<<1],cnt;
int dfn[N],dep[N],tot,fx[N][20],ans[N],ttot;
bool yz[N];
struct edge{int u,v;}e[N];
struct OP{int op,x;}p[N];
struct rmm{int fx,l,r,dis;}fa[N];
namespace Wisadel
{
int Wfind(int x)
{
if(x==fa[x].fx) return x;
return fa[x].fx=Wfind(fa[x].fx);
}
void Wadd(int u,int v)
{
to[++cnt]=v;
ne[cnt]=hh[u];
hh[u]=cnt;
}
void Wdfs(int u,int fa)
{
fx[u][0]=fa,dfn[u]=++tot,dep[u]=dep[fa]+1;
fo(i,1,18) fx[u][i]=fx[fx[u][i-1]][i-1];
for(int i=hh[u];i!=-1;i=ne[i])
{
int v=to[i];
if(v==fa) continue;
Wdfs(v,u);
}
}
int Wlca(int x,int y)
{
if(dep[x]<dep[y]) swap(x,y);
fu(i,18,0) if((1<<i)<=dep[x]-dep[y]) x=fx[x][i];
if(x==y) return x;
fu(i,18,0) if(fx[x][i]!=fx[y][i]) x=fx[x][i],y=fx[y][i];
return fx[x][0];
}
int Wgdis(int u,int v)
{
if(u==v) return 0;
return dep[u]+dep[v]-2*dep[Wlca(u,v)];
}
void Wmerge(int i)
{
int u=Wfind(e[i].u),v=Wfind(e[i].v);
fa[u].fx=v;
int maxx=max(Wgdis(fa[u].l,fa[v].l),Wgdis(fa[u].l,fa[v].r));
maxx=max(maxx,max(Wgdis(fa[u].r,fa[v].l),Wgdis(fa[u].r,fa[v].r)));
maxx=max(maxx,max(fa[u].dis,fa[v].dis));
if(Wgdis(fa[u].l,fa[v].l)==maxx){
fa[v].dis=Wgdis(fa[u].l,fa[v].l),
fa[v].r=fa[u].l;
return;
}
if(Wgdis(fa[u].r,fa[v].l)==maxx){
fa[v].dis=Wgdis(fa[u].r,fa[v].l),
fa[v].r=fa[u].r;
return;
}
if(Wgdis(fa[u].l,fa[v].r)==maxx){
fa[v].dis=Wgdis(fa[u].l,fa[v].r),
fa[v].l=fa[u].l;
return;
}
if(Wgdis(fa[u].r,fa[v].r)==maxx){
fa[v].dis=Wgdis(fa[u].r,fa[v].r),
fa[v].l=fa[u].r;
return;
}
if(fa[u].dis==maxx){
fa[v].dis=fa[u].dis,
fa[v].l=fa[u].l,fa[v].r=fa[u].r;
return;
}
}
short main()
{
freopen("block.in","r",stdin),freopen("block.out","w",stdout);
n=qr,m=qr;
memset(hh,-1,sizeof hh);
fo(i,1,n)fa[i]={i,i,i,0};
fo(i,1,n-1)
e[i].u=qr,e[i].v=qr,Wadd(e[i].u,e[i].v),Wadd(e[i].v,e[i].u);
Wdfs(1,0);
fo(i,1,m)
{
p[i].op=qr,p[i].x=qr;
if(p[i].op==1) yz[p[i].x]=1;
}
fo(i,1,n-1) if(!yz[i]) Wmerge(i);
fu(i,m,1)
if(p[i].op==1) Wmerge(p[i].x);
else
{
int _=p[i].x,__=Wfind(_);
ans[++ttot]=max(Wgdis(fa[__].l,_),Wgdis(fa[__].r,_));
}
fu(i,ttot,1) printf("%d\n",ans[i]);
return Ratio;
}
}
int main(){return Wisadel::main();}
C. 军队
题面挺抽象的。
大概就是划分成两个问题,一是需要
赛时没想到扫描线,只会
点击查看代码
#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=998244353;
int n,m,c,k,q,tmp;
ll a[N],b[N],s1[N],s2[N];
int len[N<<2],sum[N<<2],mx[N<<2];
struct rmm{int l,r,v;};
vector<rmm>upd[N];
namespace Wisadel
{
#define ls (rt<<1)
#define rs (rt<<1|1)
#define mid ((l+r)>>1)
void Wpushup(int rt)
{
int tt=min(sum[ls],sum[rs]);
sum[ls]-=tt,sum[rs]-=tt;
mx[ls]-=tt,mx[rs]-=tt;
sum[rt]+=tt;
mx[rt]=max(mx[ls],mx[rs])+sum[rt];
}
void Wbuild(int rt,int l,int r)
{
len[rt]=r-l+1;
if(l==r) return;
Wbuild(ls,l,mid),Wbuild(rs,mid+1,r);
}
void Wupd(int rt,int l,int r,int x,int y,int v)
{
if(x<=l&&r<=y){sum[rt]+=v,mx[rt]+=v;return;}
if(x<=mid) Wupd(ls,l,mid,x,y,v);
if(y>mid) Wupd(rs,mid+1,r,x,y,v);
Wpushup(rt);
}
int Wq(int rt,int l,int r,int x)
{
x+=sum[rt];
if(x>=k) return len[rt];
if(l==r) return 0;
int res=0;
if(mx[ls]+x>=k) res+=Wq(ls,l,mid,x);
if(mx[rs]+x>=k) res+=Wq(rs,mid+1,r,x);
return res;
}
#undef mid
short main()
{
// freopen(".in","r",stdin),freopen(".out","w",stdout);
freopen("army.in","r",stdin),freopen("army.out","w",stdout);
n=qr,m=qr,c=qr,k=qr,q=qr;
fo(i,1,c)
{
int x=qr,y=qr,xx=qr,yy=qr;
upd[x].push_back({y,yy,1});
upd[xx+1].push_back({y,yy,-1});
}
Wbuild(1,1,m);
fo(i,1,n)
{
for(auto x:upd[i]) Wupd(1,1,m,x.l,x.r,x.v);
int tt=Wq(1,1,m,0);
a[i]=m-tt;
b[i]=min(a[i],m-a[i]);
}
sort(b+1,b+1+n);
fo(i,1,n) s1[i]=s1[i-1]+b[i]*b[i],s2[i]=s2[i-1]+b[i];
while(q--)
{
int x=qr,y=qr,mid=y/2;
int pos=upper_bound(b+1,b+1+n,mid)-b;
if(pos==n+1)
printf("%lld\n",1ll*((s2[n]-s2[n-x])*y-(s1[n]-s1[n-x])));
else if(pos<=n-x+1)
printf("%lld\n",1ll*x*(y-mid)*mid);
else printf("%lld\n",1ll*(n-pos+1)*(y-mid)*mid+1ll*(s2[pos-1]-s2[n-x])*y-1ll*(s1[pos-1]-s1[n-x]));
}
return Ratio;
}
}
int main(){return Wisadel::main();}
D. 棋盘
逆天要 4 个栈。
一眼简单,再一眼困难。
可恶啊赛时没想到过河卒(忘得挺彻底的,遂只打暴力 bfs,只过
用过河卒的方法每次清空 dp 数组可以拿到 30pts 的暴力分。
40pts 代码
#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=1e5+5;
const int mod=998244353;
int n,q,to,ans;
int dh[N][22],st=1,ed;
int yz[N][22],f[N][22];
namespace Wistask
{
void Wdfs(int nowh,int nowl)
{
if(nowh==ed)
{
if(nowl==to) ans=(ans+1)%mod;
return;
}
if(nowl==1)
{
if(dh[nowh+2][2]!=1) Wdfs(nowh+2,2);
return;
}
else
{
if(dh[nowh+2][1]!=1) Wdfs(nowh+2,1);
return;
}
}
short main()
{
while(q--)
{
string op,s;cin>>op;
if(op=="Add")
{
cin>>s;ed++;
fo(i,0,n-1) dh[ed][i+1]=(s[i]=='#');
}
else if(op=="Del") st++;
else
{
int a=qr;to=qr;ans=0;
if(st>ed||(ed-st)&1||dh[st][a]==1){printf("0\n");continue;}
Wdfs(st,a);
printf("%d\n",ans);
}
}
return Ratio;
}
}
namespace Wisadel
{
short main()
{
// freopen(".in","r",stdin),freopen(".out","w",stdout);
freopen("chess.in","r",stdin),freopen("chess.out","w",stdout);
n=qr,q=qr;
// printf("%lf\n",1.0*sizeof(dh)/1024/1024);
if(n==1)
{
while(q--)
{
string op,s;cin>>op;int a,b;
if(op=="Add") cin>>s;
else if(op=="Del") continue;
else a=qr,b=qr,printf("0\n");
}
return Ratio;
}
if(n==2) return Wistask::main();
while(q--)
{
string op,s;cin>>op;
if(op=="Add")
{
cin>>s;ed++;
fo(i,0,n-1) dh[ed][i+1]=(s[i]=='#');
}
else if(op=="Del") st++;
else
{
int a=qr;to=qr;ans=0;
memset(f,0,sizeof f);
if(dh[st][a]!=1) f[st][a]=1;
else {printf("0\n");continue;}
fo(i,st+1,ed) fo(j,1,n)
{
if(dh[i][j]) continue;
if(i-st>=2)
{
if(j>1) f[i][j]=(f[i][j]+f[i-2][j-1])%mod;
if(j+1<=n) f[i][j]=(f[i][j]+f[i-2][j+1])%mod;
}
if(i-st>=1)
{
if(j>2) f[i][j]=(f[i][j]+f[i-1][j-2])%mod;
if(j+2<=n) f[i][j]=(f[i][j]+f[i-1][j+2])%mod;
}
}
printf("%d\n",f[ed][to]);
}
}
return Ratio;
}
}
int main(){return Wisadel::main();}
末
直接从 CSP 模拟晋升到 NOIP 模拟,难度直线上升。
看到 pdf 就觉得不对劲了,不是牛犇外校大佬出题就是逆天私题,果然被薄纱了。
打暴力手法还有欠缺,不过好在今天学到了新(确信 东西——树上连通块转移直径,不算荒了。
越来越冷了,虽然空调不直对着我(要真直对着估计早寄了,感觉这样下去过几天就也感冒发烧了,悲。
完结撒花~
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· 单线程的Redis速度为什么快?
· 展开说说关于C#中ORM框架的用法!
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库
· SQL Server 2025 AI相关能力初探