USACO 选做

\(\text{Permutation G}\)

题目描述

思路点拨

再开始的局面显然是一个三角形 \((A_i,A_j,A_k)\) ,考虑新增一个节点在什么情况下合法,这里分两类讨论:

  • 新增节点 \(A_l\) ,满足 \(A_l\) 在三角形 \((A_i,A_j,A_k)\) 的内部。

  • 新增节点 \(A_l\) ,满足 \(A_i/A_j/A_k\) 在三角形 \((A_l,A_j,A_k)/(A_i,A_l,A_k)/(A_i,A_j,A_l)\) 的内部。

不然就容易画图证明画不出三个线条。并且我们的局面每时每刻会保持一个三角形的状态。

考虑动态规划,设 \(f[i][j][k][w]\) 表示目前考虑到以 \(A_i,A_j,A_k\) 三个节点为外围的三角形,目前三角形内部已经选择了 \(w\) 个节点。转移顺序可以由 \(w\) 从小到大转移,具体转移分两类:

  • 选择的节点在三角形 \((A_i,A_j,A_k)\) 的内部

  • 枚举一个新的节点 \(A_l\) 并且判断是否合法,可以转移。

相信容易写出转移式。现在还有一个细节,就是怎么判断一个节点 \(A_l\) 是否在 \((A_i,A_j,A_k)\) 中,我采取的方法是判断三角形 \((A_i,A_j,A_l),(A_i,A_k,A_l),(A_j,A_k,A_l)\) 的面积和是否等于 \((A_i,A_j,A_k)\) 的面积。对于单个三角形的面积因为保证三点不会共线,所以使用水平宽铅垂高求会比较简单。单次可以 \(O(1)\) 判断,但是因为涉及大量浮点数运算的原因常数较大,建议预处理出来。

时间复杂度分析发现对于每一个状态,我们枚举一个三角形外的节点 \(A_l\) 需要花费 \(O(n)\) 的时间,所以时间复杂度为 \(O(n^5)\) 。本题中 \(n \leqslant 40\) 所以可以轻松通过。

\(\text{Cowpatibility G}\)

题目描述

思路点拨

考虑容斥,问题转换为了求包含 \(k\) 个给定的冰激凌的奶牛有多少个。将冰激凌的品种哈希之后放入 unordered_map 里面看出现次数即可。时间复杂度 \(O(n)\) ,但是 \(160\) 的常数。

代码比较短所以贴一个:

#include<bits/stdc++.h>
#define int unsigned long long
#define ll long long
using namespace std;
const int MAXN=5e4+5,base=1e6+5; 
int n,a[MAXN][5];
long long ans;
unordered_map<int,int> cnt;
signed main(){
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=0;j<5;j++) cin>>a[i][j];
		sort(a[i],a[i]+5);
		for(int j=0;j<(1<<5);j++){
			int popcount=0,hsh=0;
			for(int k=0;k<5;k++)
				if(j&(1<<k)){
					popcount++;
					hsh=hsh*base+a[i][k];
				} 
			cnt[hsh]++;
			if(popcount&1) ans=ans-cnt[hsh];
			else ans=ans+cnt[hsh];
		}
	}
	cout<<ans;
	return 0;
}

\(\text{Palindromes P}\)

题目描述

思路点拨

先想一下对于一个长度为 \(n\) 序列如何求其答案。如果H牛和G牛的出现次数都是奇数,那么无解。我们考虑让H牛达到一个回文的状态,此时的G牛也会回文。假设H牛的出现下标分别为 \(a_1,a_2,...,a_m\) 。那么如果两个位置互相回文的话,一定满足 \(p+q=n+1\) 。对于我们目前的状态我们肯定不会改变H牛的相对位置,所以只需要满足 \(\forall i,a_i+a_{m-i+1}=n+1\) 即可。如果 \(m\) 是奇数的话,\(\dfrac{m+1}{2}\) 头牛特别考虑一下。

怎么样构造方案才可以让距离之和最小。考虑对于一个序对 \((a_i,a_{m-i+1})\) ,假设 \(a_i < a_{m-i+1}\) ,我们希望 \(a_i\) 移动到位置 \(p\) ,距离花费就是 \(|a_i-p|+|a_{m-i+1}-(n+1-p)|=|p-a_i|+|p-(n+1-a_{m-i+1})|\) ,所以只要 \(p \in [a_i,n+1-a_{m-i+1}]\) 就可以达到最小值,也就是 \(|a_i+a_{m-i+1}-(n+1)|\) 。但是对于全部的 \(a\) 是否可以让各自 \(p\) 都落在自己的最优区间内不一定可以保证。我们可以根据 \(a_i\) 在序列中为位置在序列的左边右边让 \(p=a_i\) 或者 $ n+1-a_{m-i+1}$ 发现这样是合法的,我们就通过构造的方式使得区间的贡献可以达到最优也就是 \(\sum_{i<\frac{m}{2}}|a_i+a_{m-i+1}-(n+1)|\) ,但是如果 \(m\) 为奇数,中间元素价值另说。

现在我们对全部的区间这个权值计数。但是存在一个问题,按照我们常规的枚举方法,固定一个左端点,右端点从小到大这样枚举会改变H牛的配对方式。所以我们考虑枚举区间最中间的一头牛或者两头牛,这样时间复杂度没有改变并且对于同一个中点奶牛的配对方式是固定的。我们将这个值放入树状数组中优化计算即可。时间复杂度 \(O(n^2 \log n)\) ,注意常数优化。

\(\text{Tickets P}\)

题目描述

思路点拨

考虑每一时刻我们可以到达的区间是连续的,我们最初的想法就是求出区间的左端点扩展到 \(1\) 节点的距离 \(dis1_i\) 和右端点扩展到 \(n\) 节点的距离 \(disn_i\) 。然后将两个权值加和 \(dis1_i+disn_i\) 。这样发现答案会算大一些,因为这两个路径可能相交了,有的路径本来只需要算一遍权值这里算了两遍。

考虑令 \(f_i=dis1_i+disn_i\) ,这样可以更新 \(f_i=\sum_{i 可以到达 j} f_j+w\) 。这个转移有环,使用最短路优化一下。

现在时间复杂度可以做到 \(O(nK \log n)\) ,瓶颈在于边太过了。可以 \(\text{ST}\) 表优化连边,做到 \(O(K \log^2 n)\)

\(\text{Springboards G}\)

题目描述

思路点拨

这题有很多同学使用了 \(\text{CDQ}\) 分治的做法,时间复杂度 \(O(n \log^2 n)\) ,省事但是不优。

考虑按照 \(x\) 从小到大为第一关键字转移,\(y\) 从小到大为第二关键字转移。我们就可以保证转移的对象满足 \(x_j<x_i\) ,但是不可以保证转移对象 \(y_j<y_i\) 。所以我们与此同时套一个动态开点权值线段是来保证 \(y_j<y_i\) 。转移式可以写为:

\[f_{i}=\min\{f_{j}+(x_i-x_j)+(y_i-y_j)\}=x_i+y_i-\min\{f_j-x_j-y_j\} \]

现在就好放进线段树里了。

问题是使用了跳板之后假设到了 \(X_i,Y_i\) 的位置,这样直接插入线段树里会破坏我们的下标的单调性。我们可以把相关的信息暂时插入到一个双关键字的优先队列里面,可以使用的时候再拿出来插入线段树。

时间复杂度 \(O(n \log n)\) ,代码非常短。

posted @ 2024-01-05 11:10  Diavolo-Kuang  阅读(17)  评论(0编辑  收藏  举报