NOIP2024 前集训:多校A层冲刺NOIP2024模拟赛21

前言

image

rk 历程:\(11\to 9\to 8\to 7\),原因是部分人的 T1 假做法被卡(感觉目前这些不二分也不 DP(特指 Hangry 这样的 \(O(n^4)\) DP)都能卡)。

T2 建图建错了(没判谁是父亲也没建双向边)暴力死了,挂了 \(24\)

我是唯一一个打了 T3 启发正解部分分但没有写出正解的人……

T4 部分分都不会,润了。

T1 送信卒

单调性过于显然,所以直接二分答案即可,check 直接写 dijkstra,复杂度 \(O(m\log m\log n)\),因为是 double 所以要写 eps。

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
using namespace std;
const int N=110,M=1e4+10; const double eps=1e-8;
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,sx,sy,tx,ty,tot,head[M],nxt[M<<2],to[M<<2];
bool w[M<<2],vis[M],a[N][N]; double s,l,r=1e5,mid,dis[M];
struct aa
{
	int pos; double dis;
	inline bool operator < (const aa a) const {return dis-a.dis>eps;}
}; priority_queue<aa>q;
inline void add(int x,int y,int z)
{nxt[++tot]=head[x],to[tot]=y,w[tot]=z,head[x]=tot;}
inline int calc(int x,int y) {return (x-1)*m+y;}
inline bool check(int x,int y) {return x>=1&&x<=n&&y>=1&&y<=m&&!a[x][y];}
inline double calc(int x) {return x?mid:1;}
inline bool check()
{
	fill(dis+1,dis+1+n*m,1e9),fill(vis+1,vis+1+n*m,0);
	for(q.push({calc(sx,sy),dis[calc(sx,sy)]=0});!q.empty();)
	{
		int x=q.top().pos; q.pop(); if(vis[x]) continue; vis[x]=1;
		for(int i=head[x],y;y=to[i];i=nxt[i])
			if(dis[y]-dis[x]-calc(w[i])>eps)
				dis[y]=dis[x]+calc(w[i]),q.push({y,dis[y]});
	}
	return dis[calc(tx,ty)]-s>=eps;
}
signed main()
{
	freopen("msg.in","r",stdin),freopen("msg.out","w",stdout);
	read(n,m,sx,sy,tx,ty);
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) read(a[i][j]);
	for(int i=1;i<=n;i++) for(int j=1;j<=m;j++) if(!a[i][j])
	{
		if(check(i,j-1)) add(calc(i,j),calc(i,j-1),0);
		if(check(i,j+1)) add(calc(i,j),calc(i,j+1),0);
		if(check(i-1,j)) add(calc(i,j),calc(i-1,j),1);
		if(check(i+1,j)) add(calc(i,j),calc(i+1,j),1);
	}
	for(scanf("%lf",&s);r-l>eps;) mid=(l+r)/2.0,check()?r=mid:l=mid;
	printf("%.3lf",l);
}

T2 共轭树图

对于每一个点钦定一个 \(dep\),那么 \(x\) 在生成树中的深度可以为 \([1,dep_x]\),既可以和与他联通的任意一个祖先连边。

\(f_{x,i}\) 表示点 \(x\) 向上连深度不超过 \(i\) 的祖先的方案数,这本质上是一个前缀和优化,那么有:

\[f_{x,i}=\prod_{y\in son_x}\sum_{j=1}^if_{y,j+1} \]

复杂度 \(O(n^2)\)

点击查看代码
#include<bits/stdc++.h>
#define ll long long
#define endl '\n'
#define sort stable_sort
#define pb push_back
using namespace std;
const int N=3e3+10,P=998244353;
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,f[N][N]; ll ans=1; vector<int>e[N];
inline int mod(int x,int y) {return (x+=y)>=P?x-P:x;}
inline void dfs(int x,int dep)
{
	for(int y:e[x]) dfs(y,dep+1); f[x][1]=1;
	for(int i=1;i<=dep;f[x][i]=mod(f[x][i],f[x][i-1]),f[x][++i]=1)
		for(int y:e[x]) f[x][i]=1ll*f[x][i]*f[y][i+1]%P;
}
signed main()
{
	freopen("reflection.in","r",stdin),freopen("reflection.out","w",stdout);
	read(n); for(int i=1,x,y;i<n;i++) read(x,y),x<y?e[y].pb(x):e[x].pb(y);
	dfs(n,0); for(int i:e[n]) (ans*=f[i][1])%=P; write(ans);
}

T3 摸鱼军训

考虑对于每个点单独考虑,定义 \(pre_i\) 表示 \(i\) 这个点前面有多少个 \(>i\) 的点,那么若 \(k<pre_i\),答案就是 \(pre_i-k\),现在需要考虑 \(k>pre_i\) 的怎么做,这是可以用树状数组或线段树维护的。

发现每次操作 \(i\) 会停到后面第一个 \(>i\) 的位置的前一个位置,那么问题就迎刃而解了,找到第一个前缀中 \(>i\) 的的数量 \(=k\) 的位置 \(pos\),那么答案就是 \(pos-k\),这是可以在值域线段树上二分维护的。

关于我赛时想到结论但是不知道用数据结构维护这件事。

T4 神奇园艺师

并不想调,咕了。

posted @ 2024-11-13 08:13  卡布叻_周深  阅读(26)  评论(0编辑  收藏  举报