2024.8.10

只交了俩题,\(0+30+0+70\)

T1 星际旅行

呃呃我以为这题没啥人会,没想到高分率还挺高的,还是太菜了。

给一个无向图,\(n\) 个点 \(m\) 条边,有自环无重边,问有多少种不同方案使恰有 \(m-2\) 条边被经过 \(2\) 次,恰有 \(2\) 条边被经过 \(1\) 次。

想到一笔画了,但想不下去了,这方面都没咋研究过。

原题可以转化为,删去两条边,原图可存在欧拉路径。

注意到新图中所有点的度数为偶数,分情况讨论:

\(2\) 个自环、\(1\) 个自环和一条边、\(2\) 条有公共定点的边做贡献。

然后注意判断图的连通性,注意是边连通不是点连通。

T2 砍树

T3 超级树

T4 成绩单

场上的 \(\text{dp}\) 假了,大样例过不去,但是数据太水小点都过了,于是有 \(70\)

将长为 \(n\) 的序列 \(w\)\(k\) 次消除,消除的过程是从序列中抽 \(k\) 个连续段,抽出后自动补位。每次消除的代价为 \(a \times k + b \times \sum_{i = 1} ^ k (max_i - min_i) ^ 2\),其中 \(a,b\) 为常数,\(k\) 可以自定,\(max_i\)\(min_i\)\(\forall i\in[1,k]\),第 \(i\) 次抽取的连续段中的最大值和最小值,求最小代价。

\(n \leq 50\)\(a \leq 1500\)\(b \leq 10\)\(w_i \leq 1000\)

一眼的思路是设 \(f_{i,j,k}\) 表示把 \([i,j]\) 全部消掉并且用了 \(k\) 次的最小价值,那答案就是 \(f_{1,n,k}\) 了,跑一个 \(k\) 去算一个最小值,转移就从中间转移然后统计两边的答案。考场上感觉没啥问题,其实现在也觉得没啥问题。哦其实有点问题,这样转移其实钦定一个大段的消除过程就是中间消一个连续段然后把其余部分拼起来。但一个大段的消除过程可以是中间扣好几个部分,然后把剩余好几个散块连起来共同取最大最小,那原方法就错了。

所以发现取法是非常多的,但是答案只由这些散段的最大最小值来贡献,那方程里必然带上最大最小值。设 \(f_{l,r}\) 就表示把 \([l,r]\) 全消掉的最小代价, \(g_{l,r,maxn,minn}\) 表示把 \([l,r]\) 这个区间随便扣掉一些部分后,剩下的散块中的最大值为 \(maxn\) ,最小值为 \(minn\) 时最后一步全扣掉(把 \([l,r]\) 扣剩下的扣完)的最小代价。然后枚举一下 \(maxn\)\(minn\) 来算一个最小值

\[f_{l,r} = \min(g_{l,r,maxn,minn}+a+b(maxn-minn)^2) \]

这是汇总答案,考虑枚举移动区间,由小区间汇总大区间:原区间为 \([l,r]\),加入右边新点 \(w_{r+1}\),就会有两种情况:

  • 算到之前被扣掉的部分里,即不在最后一步删除。这样必然不会对 \(maxn,minn\) 产生影响,但是需要考虑 \([r+1,k]\) 区间上的答案。

    \[g_{l,k,maxn,minn} \Leftarrow \min(g_{l,k,maxn,minn},g_{l,r,maxn,minn} + f_{r+1,k}) \]

    然后你会发现你可以把 \(r\)\(k\) 换一下,变成一个小到大的贡献转移:

    \[g_{l,r,maxn,minn} \Leftarrow \min(g_{l,r,maxn,minn},g_{l,k,maxn,minn}+f_{k+1,r}) \]

  • 留在剩下的散块里,在最后一步删除。这样有可能对 \(maxn,minn\) 影响,但是也有可能被一并消除

\[g_{l,r+1,\max(maxn,w_{r+1}),\min(minn,w_{r+1})} \Leftarrow \min(g_{l,r,maxn,minn}) \]

注意值域比较大,离散化一下存在数组里,算答案的时候调出来原值。

	sort(d+1,d+1+n);
	int tot = unique(d+1,d+1+n)-d-1;
	for(int i{1};i<=n;i++) a[i] = lower_bound(d+1,d+1+tot,a[i])-d,ff[i][i] = aa;
	memset(g,0x3f3f3f3f,sizeof(g));
	memset(ff,0x3f3f3f3f,sizeof(ff));
	for(int i{1};i<=n;i++) g[i][i][a[i]][a[i]] = 0;
	for(int len{1};len<=n;len++)
		for(int l{1};l+len-1<=n;l++)
		{
			int r = l+len-1;
			for(int minn{1};minn<=tot;minn++)
				for(int maxn{minn};maxn<=tot;maxn++)
				{
					for(int k{l};k<r;k++)
						g[l][r][maxn][minn] = min(g[l][k][maxn][minn]+ff[k+1][r],g[l][r][maxn][minn]);
					g[l][r+1][max(maxn,a[r+1])][min(minn,a[r+1])] = 
						min(g[l][r][maxn][minn],g[l][r+1][max(maxn,a[r+1])][min(minn,a[r+1])]);
					ff[l][r] = min(ff[l][r],g[l][r][maxn][minn] + aa + bb * (d[maxn]-d[minn])*(d[maxn]-d[minn]));
//					printf("f[%lld][%lld] = %lld\n",l,r,ff[l][r]);
				}
		}
	writeln(ff[1][n]);
posted @ 2024-09-14 21:17  WanGMiNgWeI  阅读(6)  评论(0编辑  收藏  举报