NOIP2024 前集训:【MX-S7】梦熊 NOIP 2024 模拟赛 3 & SMOI Round 2(同步赛)

前言

music
《人是_》

去往 所有 命运 风暴之中的盲童

你来自火山炙热 与苦寒的深海

生本 就是 意外 硬币反选为尘埃

为侥幸可以相爱 造了船 移着山

出征是古老的宿命

人将赤足踏入夜晚

只有我可以来决定 我以何种姿态

让死亡觊觎我

让恐惧亲吻我

来摧毁我深爱的一切

可仍夺不走我的选择

弹指间湮灭我

但命运打不败活着

让生命如剧烈的烟火

璀璨熄灭前也将点亮

孩童的双眸

未知 摊开 棋局 舍弃昨日才可破

再见了我的月光 我的蓝 我的爱

钢铁的巨兽在轰鸣 我们拒绝走入夜晚

破碎是新生的约定 我便愿为尘埃

让死亡觊觎我

让恐惧亲吻我

来摧毁我深爱的一切

可仍夺不走我的选择

弹指间湮灭我

但命运打不败活着

让生命如剧烈的烟火

璀璨熄灭前也将点亮

孩童的双眸

若巨浪已淹没了来路 我是帆 亦是舟

是微渺 的希望

我们依然前行 没有光指引

往前吧 失去吧 不要停留

让时空消亡我

你无需记得我

来摧毁我深爱的一切

可仍夺不走我的选择

弹指间湮灭我

但命运打不败活着

是微茫中高歌的族类

生命像烟火那就点亮

孩童的双眸

未来的瞳孔

昨天塞给我们一场洛谷上梦熊的比赛,\(8\) 点半才开始本来应该 \(1\) 点结束,然后飞飞:

有没有想中午留下把模拟赛打完再走的?(停顿一下,已经有人开始举手)打消这个念头。

T1 抽象死了,本来想着 T1 能放点什么结果上来一道分讨,真不想做大样例还死活过不去,恼了直接把 hangry 代码弄下来了,然后恍然大悟,然后 hangry 恼了,所以最后没交怕把他棕了……

T2 是一眼题,严格简单于 T1,直接上树剖加树形 DP 就做完了,赛时不知道自己打的是换根 DP,赛后经过一番讨论才知道自己打的是一个不需要换根的换根 DP,T2 用的时间 \(\times 10\) 都没 T1 用的时间长。

T3 赛时没时间看了,下午和晚上才改出来。

P11323 【MX-S7-T1】「SMOI-R2」Happy Card

赛时是唐了,可能就是当时太困了看到分讨就不想做了。

考虑“炸弹”也是唐氏,直接把“三带一”加强成可以带相同花色的,现在就只剩三种操作了,当然是优先出“三带一”。

\(cnt_1=\sum\limits_{i=1}^n[v_i\bmod 3=1],cnt_2=\sum\limits_{i=1}^n[v_i\bmod 3=2],cnt_3=\sum\limits_{i=1}^n\lfloor\dfrac{n}{3}\rfloor\),显然有 \(cnt_1+cnt_2+cnt_3=\sum\limits_{i=1}^nv_i\)

先将已有的 \(cnt_1\)\(cnt_3\) 配对,\(1\)\(1\)\(1\)\(3\) 配对。

之后若 \(cnt_3\) 有剩余就和 \(cnt_2\) 配对,\(1\)\(2\)\(2\)\(3\) 配对,若剩余 \(1\)\(2\)\(1\)\(3\) 配对的就是多出一个 \(1\),另 \(cnt_1+1\)

最后只会有只剩余 \(3\) 和只剩余 \(1,2\) 两种情况,对于只剩余 \(3\) 的,发现没 \(4\)\(3\) 可以用 \(3\) 次消掉,剩下的若有余数,剩 \(3\)\(3\) 则需要 \(3\) 次,否则需要 \(2\) 次;对于只剩 \(1,2\) 的无法配对,需要 \(cnt'_1+cnt'_2\) 次。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int T,n,cnt1,cnt2; ll cnt3,ans;
signed main()
{
	for(read(T);T;T--,write(ans),puts(""),ans=cnt1=cnt2=cnt3=0)
	{
		read(n); for(int i=1,a;i<=n;i++)
			read(a),cnt1+=a%3==1,cnt2+=a%3==2,cnt3+=a/3;
		if(cnt1>cnt3) ans+=cnt3,cnt1-=cnt3,cnt3=0;
		else ans+=cnt1,cnt3-=cnt1,cnt1=0;
		if(cnt3>(cnt2<<1)) ans+=cnt2<<1,cnt3-=cnt2<<1,cnt2=0;
		else ans+=cnt3,cnt2-=cnt3+1>>1,cnt1+=cnt3&1,cnt3=0;
		if(!cnt3) ans+=cnt1+cnt2;
		else ans+=(cnt3>>2)*3,cnt3%=4,!!cnt3&&(ans+=max(2ll,cnt3));
	}
}

P11324 【MX-S7-T2】「SMOI-R2」Speaker

感觉 T2 就是严格简单于 T1。

考虑只有以下几种情况:

  • \(z\)\(x\to y\) 路径上,\(c_x+c_y+c_z-dis(x,y)\)
  • \(z\)\(x\)\(y\) 的子树中,以在 \(x\) 子树中为例:\(c_x+c_y+c_z-dis(x,y)-2dis(x,z)\)
  • \(z\)\(lca(x,y)\) 的子树内但不在 \(x\)\(y\) 的子树内,设 \(u=lca(x,z),v=lca(y,z)\),假设 \(dep_u\ge dep_v\),则答案为 \(c_x+c_y+c_z-dis(x,y)-2dis(u,z)\)
  • \(z\)\(lca(x,y)\) 的子树外,\(c_x+c_y+c_z-dis(x,y)-2dis(lca(x,y),z)\)

\(subtree_x\) 表示 \(x\) 的子树集合,\(f_{x}\) 表示 \(\max\limits_{y\in subtree_x}c_y-2dis(x,y)\)

那么前 \(3\) 种情况可并为一种:\(\max\limits_{u\in (x\to y)}c_x+c_y-dis(x,y)+f_u\)\(f_x\) 是可以直接树形 DP 求出来的,后面的东西可以直接用树剖加 ST 表维护。

现考虑第四种情况,从换根 DP 的角度,我们可以求出 \(g_x\) 表示 \(\max\limits_{y\not\in subtree_x}c_y-2dis(x,y)\),则此时答案为 \(c_x+c_y-dis(x,y)+g_{lca(x,y)}\),发现和上一种情况的格式完全相同,所以根本不需要去除 \(x\) 子树内的贡献,因为若 \(g_{x}<f_{x}\) 则第四种情况一定不优。

所以重新设 \(g_{x}\) 表示 \(\max\limits_{y=1}^{n}c_y-2dis(x,y)\),以上四种情况的答案均为 \(\max\limits_{u\in(x\to y)}c_x+c_y-dis(x,y)+g_u\)\(g_x\)\(f_x\) 的基础上再跑一遍树形 DP 求出,后面的一样用树剖加 ST 表维护。

最后就会发现打了一个不需要换根的换根 DP。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=2e5+10;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,m,tot,a[N],sz[N],fa[N],son[N],dep[N],dfn[N],top[N],mx[20][N];
int head[N],nxt[N<<1],to[N<<1],w[N<<1]; ll f[N],dis[N];
inline void add(int x,int y,int z)
{nxt[++tot]=head[x],to[tot]=y,w[tot]=z,head[x]=tot;}
inline void dfs1(int x,int t)
{
	dep[x]=dep[fa[x]=t]+1,sz[x]=1;
	for(int i=head[x],y;y=to[i];i=nxt[i]) if(y!=t)
	{
		dis[y]=dis[x]+w[i],dfs1(y,x);
		sz[x]+=sz[y],sz[y]>sz[son[x]]&&(son[x]=y);
	}
}
inline void dfs2(int x,int t)
{
	dfn[x]=++tot,top[x]=t; if(son[x]) dfs2(son[x],t);
	for(int i=head[x],y;y=to[i];i=nxt[i]) if(y!=fa[x]&&y!=son[x]) dfs2(y,y);
}
inline int lca(int x,int y)
{
	for(;top[x]!=top[y];x=fa[top[x]])
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
	return dep[x]<dep[y]?x:y;
}
inline ll getdis(int x,int y) {return dis[x]+dis[y]-(dis[lca(x,y)]<<1);}
inline void dfs3(int x)
{
	f[x]=a[x]; for(int i=head[x],y;y=to[i];i=nxt[i])
		if(y!=fa[x]) dfs3(y),f[x]=max(f[x],f[y]-(w[i]<<1));
}
inline void dfs4(int x)
{
	for(int i=head[x],y;y=to[i];i=nxt[i]) if(y!=fa[x])
		f[y]=max(f[y],f[x]-(w[i]<<1)),dfs4(y);
}
inline int getmax(int l,int r)
{int t=__lg(r-l+1); return max(mx[t][l],mx[t][r-(1<<t)+1]);}
inline int ask(int x,int y)
{
	int res=0; for(;top[x]!=top[y];x=fa[top[x]])
	{
		if(dep[top[x]]<dep[top[y]]) swap(x,y);
		res=max(res,getmax(dfn[top[x]],dfn[x]));
	}
	if(dep[x]>dep[y]) swap(x,y);
	return max(res,getmax(dfn[x],dfn[y]));
}
signed main()
{
	read(n,m); for(int i=1;i<=n;i++) read(a[i]);
	for(int i=1,x,y,z;i<n;i++) read(x,y,z),add(x,y,z),add(y,x,z);
	tot=0,dfs1(1,0),dfs2(1,1),dfs3(1),dfs4(1);
	for(int i=1;i<=n;i++) mx[0][dfn[i]]=f[i];
	for(int i=1;i<=__lg(n);i++) for(int j=1;j+(1<<i)-1<=n;j++)
		mx[i][j]=max(mx[i-1][j],mx[i-1][j+(1<<(i-1))]);
	for(int i=1,x,y;i<=m;i++,puts(""))
		read(x,y),write(a[x]+a[y]-getdis(x,y)+ask(x,y));
}

P11325 【MX-S7-T3】「SMOI-R2」Monotonic Queue

首先得把题读懂,发现性质后然后就可以直接线段树优化 DP 了。

发现若只取长度为 \(1\) 的区间最优,考虑此时有 \(c_i>0\)\([l_j=i,r_j=i]\),若 \(\exists k\in(r_j,r_{j+1}],a_k<a_i\) 就可以吃到 \(c_i\) 贡献同时正常的吃到 \((r_j,r_{j+1}]\) 的贡献,同时这样更容易避免 \(c_i<0\) 的负贡献,因为很快的从 \(l_j\) 弹出去了。

考虑 DP,设 \(f_i\) 表示钦定选择 \([i,i]\) 这一区间,有 \(f_i=\max\limits_{j=0}^{i-1}f_j+val_{[j,i]}\)

先考虑怎么求 \(val_{[j,i]}\),设 \(nxt_i\) 表示 \(i\) 后第一个 \(j\) 满足 \(a_j>a_i\),那么 \(c_i\) 的贡献就会在 \(nxt_i\) 这里吃到,所以 \(c_i\) 的贡献被吃到当且仅当 \(i\in(r_j,r_{j+1}]\wedge nxt_i\in(r_j,r_{j+1}]\)\(nxt_i\) 可以单调栈直接求出,开一个 vector 存 \(\{j\mid nxt_j=i\}\),移动到一个 \(i\) 时把 \(i\) 的 vector 的元素都取出来计算他的贡献即可。

发现这相当于对线段树进行前缀加,单点赋值维护全局最大值的操作。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
#define mid (l+r>>1)
#define ls (p<<1)
#define rs (p<<1|1)
using namespace std;
const int N=5e5+10;
template<typename Tp> inline void read(Tp&x)
{
	x=0;register bool z=true;
	register char c=getchar_unlocked();
	for(;!isdigit(c);c=getchar_unlocked()) if(c=='-') z=0;
	for(;isdigit(c);c=getchar_unlocked()) x=(x<<1)+(x<<3)+(c^48);
	x=(z?x:~x+1);
}
template<typename T,typename ...Tp> inline void read(T &x,Tp &...y){read(x);read(y...);}
template<typename Tp> inline void wt(Tp x){if(x>9)wt(x/10);putchar_unlocked((x%10)+'0');}
template<typename Tp> inline void write(Tp x){if(x<0)putchar_unlocked('-'),x=~x+1;wt(x);}
template<typename T,typename ...Tp> inline void write(T x,Tp ...y){write(x);putchar_unlocked(' ');write(y...);}
int n,a[N],c[N],sta[N]; ll ans=-1e18,val[N<<2],add[N<<2]; vector<int>e[N];
inline void pushup(int p) {val[p]=max(val[ls],val[rs]);}
inline void build(int p,int l,int r)
{
	if(l==r) return val[p]=!l?0:-1e18,void();
	build(ls,l,mid),build(rs,mid+1,r),pushup(p);
}
inline void spread(int p)
{val[ls]+=add[p],add[ls]+=add[p],val[rs]+=add[p],add[rs]+=add[p],add[p]=0;}
inline void change(int p,int l,int r,int x,ll d)
{
	if(l==r) return val[p]=d,void(); if(add[p]) spread(p);
	x<=mid?change(ls,l,mid,x,d):change(rs,mid+1,r,x,d),pushup(p);
}
inline void change(int p,int l,int r,int vl,int vr,int d)
{
	if(vl<=l&&vr>=r) return val[p]+=d,add[p]+=d,void();
	if(add[p]) spread(p); if(vl<=mid) change(ls,l,mid,vl,vr,d);
	if(vr>mid) change(rs,mid+1,r,vl,vr,d); pushup(p);
}
signed main()
{
	read(n),sta[0]=n+1,build(1,0,n);
	for(int i=1;i<=n;i++) read(c[i]); for(int i=1;i<=n;i++) read(a[i]);
	for(int i=n,top=0;i;e[sta[top]].push_back(i),sta[++top]=i--)
		while(top&&a[sta[top]]<=a[i]) top--;
	for(int i=1;i<=n;ans=max(ans,val[1]),change(1,0,n,i++,val[1]))
		for(int j:e[i]) change(1,0,n,0,j,c[j]);
	return write(ans),puts(""),0;
}

P11326 【MX-S7-T4】「SMOI-R2」XA-Game

高级博弈论,赛后连篇题解都没有,真指望我能在赛后把我赛时瞪不出来的题不看题解瞪出来?

posted @ 2024-11-25 08:48  卡布叻_周深  阅读(47)  评论(1编辑  收藏  举报