(联考)noip71

虽然考的很烂,但blog还是要写的。

T1

考场想法:最优方案显然是让这个点的每条边的颜色均匀分布,于是我就去给每条边染色去了,大样例死活过不去,然后我就爆蛋了。

好吧,还有可怜我的5pts。

正解:

由Vizing定理可知,每个点的度数为模 \(c\) 不为0,则会对最后答案产生1的贡献,求个和即可。

啥是Vizing定理和证明?我不会,所以丢blog

sb结论题

不过确实写出来的人很多,签到题三字都写在题面上了,然而我还是上来就跳了这道题...

就算不知道这个定理,自己模几组还是能推出来的。

还是懒了,本来就菜,还懒,只能说活该。

对于一些没思路的题,可以花一些时间去模几组样例,总之就是不能懒。

T2

考场想法:实在没啥好说的,因为是暴力,部分分也没拿着。

正解:

很简单,根据新加入的 \(u,v\) 的祖孙关系分类讨论,用线段树维护即可。

这里默认 \(v\) 的深度更大。

不难发现,输入的 \(u,v\) 只有两种关系:

  1. 如果 \(u,v\) 存在祖孙关系,那么画个图就可以发现,能产生贡献的就是 \(u\) 的子树,和除了 \(v\) 在这条链的儿子的子树(不算点 \(u\) 的子树)之外的点。
  2. 如果 \(u,v\) 没有祖孙关系,那么能产生贡献的点一定是在两个点的子树中。

所以只需要求个dfn序,再写个支持区间加+全局max的线段树即可。

对于1,需要找到 \(v\) 在这条链上的儿子,可以用倍增来实现。

注意题目要求,离总祭祀台最近的只能有一个,且只能是 \(u,v\) 中的一个。

考场上多次在正解门前徘徊,但终究是没有前进。

好吧,其实就是菜....

没思路的题可以画个图,模下样例。

根据一些性质进行分类讨论也是比较重要的解题思路。

T3

考场想法:题目好长,干脆弃了。

正解:

SPT+树形dp。

SPT:Shortest Path Tree ,最短路树,即记录下来最短路转移过程中 \(u\) 的前驱 \(pre_{u}\) ,然后对于所有的节点都以其 \(pre\) 为父亲节点建树,就出来了SPT。

有题目可得,点 \(u\) 仅能由其前驱过来,并且点1到其他节点的最短路只有一条,所以考虑SPT+树形dp。

先跑遍 \(dijkstra\) ,然后建SPT,在SPT上树形dp。

\(dp_{u,j}\) 表示以 \(u\) 为根的子树总共放了 \(j\) 个警察,能抓住杨吞天的最大概率。

转移前先做遍子树合并,点 \(u\) 的转移枚举点 \(u\) 放多少个警察和其子树放多少个警察即可。

Code
#include<queue>
#include<cstdio>
#include<cctype>
#include<cstring>
#define re register
const int N = 303;
const int M = 3e4+3;
#define scanf oma=scanf
using std::priority_queue;
int oma;
namespace some
{
	struct stream
	{
		template<typename type>inline stream &operator >>(type &s)
		{
			bool w=0; s=0; char ch=getchar();
			while(!isdigit(ch)){ w|=ch=='-'; ch=getchar(); }
			while(isdigit(ch)){ s=(s<<1)+(s<<3)+(ch^48); ch=getchar(); }
			return s=w?-s:s,*this;
		}
	}cin;
	int n,m,k;
	double p[N][N],ans;
	template<typename type>inline type max(type a,type b)
	{ return a>b?a:b; }
	#define debug(s) debug((char*)s)
	auto debug = [](char* s) { printf("%s\n",s); };
}using namespace some;
namespace Graph
{
	struct graph
	{
		int next;
		int to;
		int w;
	}edge[M<<1];
	struct SPT
	{
		int next;
		int to;
	}tree[M<<1];
	int cnt=1,head[N];
	auto add = [](int u,int v,int w) -> void
	{ edge[++cnt] = (graph){head[u],v,w},head[u] = cnt; };
	auto link = [](int u,int v) -> void
	{ tree[++cnt] = (SPT){head[u],v},head[u] = cnt; };
	struct my
	{
		int id,dis;
		inline bool friend operator <(const my &u,const my &v)
		{ return u.dis>v.dis; }
	};
	bool vis[N];
	int dis[N],pre[N];
	priority_queue<my>q;
	auto dijkstra = []() -> void
	{
		memset(dis,0x3f,sizeof(dis));
		q.push((my){1,dis[1] = 0});
		while(!q.empty())
		{
			int u = q.top().id; q.pop();
			if(vis[u])
			{ continue ; }
			vis[u] = true;
			for(re int i=head[u],v,w; i; i=edge[i].next)
			{
				v = edge[i].to,w = edge[i].w;
				if(dis[v]>dis[u]+w)
				{
					dis[v] = dis[u]+w,pre[v] = u;
					q.push((my){v,dis[v]});
				}
			}
		}
	};
	int du[N];
	double dp[N][N],bag[N];
	void dfs(int u)
	{
		if(!head[u])
		{
			for(re int i=1; i<=k; i++)
			{ dp[u][i] = p[u][i]; }
			return ;
		}
		for(re int i=head[u]; i; i=tree[i].next)
		{ dfs(tree[i].to); }
		memset(bag,0,sizeof(bag));
		for(re int i=head[u]; i; i=tree[i].next)
		{
			for(re int j=k; ~j; j--)
			{
				for(int x=0; x<=j; x++)
				{ bag[j] = max(bag[j],bag[j-x]+dp[tree[i].to][x]); }
			}
		}
		for(re int i=1; i<=k; i++)
		{ bag[i] /= 1.0*du[u]; }
		for(re int i=1; i<=k; i++)
		{
			dp[u][i] = bag[i];
			for(re int j=0; j<=i; j++)
			{ dp[u][i] = max(dp[u][i],bag[j]*(1-p[u][i-j])+p[u][i-j]); }
		}
	}
}using namespace Graph;
namespace OMA
{
	auto main = []() -> signed
	{
		freopen("arrest.in","r",stdin); freopen("arrest.out","w",stdout);
		cin >> n >> m >> k;
		for(re int i=1,u,v,w; i<=m; i++)
		{ cin >> u >> v >> w; add(u,v,w),add(v,u,w); }
		dijkstra();
		cnt = 1; memset(head,0,sizeof(head));
		for(re int i=2; i<=n; i++)
		{ link(pre[i],i); du[pre[i]]++; }
		for(re int i=1; i<=n; i++)
		{
			for(re int j=1; j<=k; j++)
			{ scanf("%lf",&p[i][j]); }
		}
		dfs(1);
		//debug("fuck\n");
		/*for(re int i=1; i<=n; i++)
		{
			for(re int j=1; j<=k; j++)
			{ printf("%0.6lf ",dp[i][j]); }
			printf("\n");
		}*/
		printf("%0.6lf\n",dp[1][k]);
		return 0;
	};
}
signed main()
{ return OMA::main(); }

T4

考场想法:式子好长好ex,弃了弃了

正解:

image

\[\begin{aligned} &\sum_{i=l}^{r}[2|i]=\frac{r}{2}-\frac{l-1}{2} \\ &\sum_{i=l}^{r}[3|i]=\frac{r}{3}-\frac{l-1}{3} \\ &\sum_{i=l}^{r}i^{2}=\sum_{i=1}^{r}i^{2}-\sum_{i=1}^{l-1}i^{2} \\ &=\frac{r\left(r+1\right)\left(2r+1\right)}{6}-\frac{l\left(l-1\right)\left(2l-1\right)}{6} \end{aligned} \]

sb测试点分治

其实看数据范围后,就应该想到sb测试点分治,然而我直接弃了。

所以考场上如何推出这样的式子???

打表yyds!

这场考试对待后两题的态度不对,畏难心理导致跳题,一些该拿的部分分也没有拿到。

前两题比较简单,但仍然没拿多少分,一方面思考方向有问题,另一方面还是自己懒,前两题都可以模样例模出来,但自己还是没有写出来...

还是菜,一些比较普通的套路,和思考方向都没有,多积累一下把...

posted @ 2021-10-08 07:50  -OMA-  阅读(68)  评论(0编辑  收藏  举报
浏览器标题切换
浏览器标题切换end