ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

题解:USACO 2021 OPEN Gold

2021-09-12 21:36:24  阅读:198  来源: 互联网

标签:pre forn Gold Area int 题解 sum OPEN dp


T1 - United Cows of Farmer John

先维护一下每个元素前面和后面第一个相同的位置,分别记作 \(pre_i\) 和 \(nxt_i\) 。

那么,一个区间 \([l, r]\) 满足题意的充要条件就是 \(nxt_l > r \And pre_r < l\) 。

考虑枚举左端点,用一个树状数组维护右端点的个数。

从左到右枚举 \(l\) , 对于每个 \(pre_r < l\) 的 \(r\) ,将 \(r\) 这一位置在树状数组上加一,这一部分用双指针维护。

每次的答案就是树状数组上区间 \([l, nxt_l]\) 上的和。

时间复杂度 \(\mathcal O (n\log n)\) 。

int n, b[N], pre[N], nxt[N], ton[N], id[N];
inline bool cmp(int A, int B) {return pre[A] < pre[B];}
struct BIT {
	int val[N], A, R;
	inline void upd(int p, int k) {while(p <= R) val[p] += k, p += p & -p;}
	inline int qry(int p) {A = 0; while(p) A += val[p], p -= p & -p; return A;}
} ZT;
int main() {
	Rdn(n);
	forn(i,1,n) Rdn(b[i]), id[i] = i;
	forn(i,1,n) pre[i] = ton[b[i]], ton[b[i]] = i;
	forn(i,1,n) ton[i] = n + 1;
	form(i,n,1) nxt[i] = ton[b[i]], ton[b[i]] = i;
	ZT.R = n + 1;
	sort(id + 1, id + n + 1, cmp);
	int r = 1; i64 res = 0;
	forn(l,1,n) {
		while(r <= n && pre[id[r]] < l) ZT.upd(id[r], 1), ++r;
		res += ZT.qry(nxt[l]) - ZT.qry(l - 1) - 1; 
	}
	Wtn(res, '\n'); flush();
	return 0;
}

T2 - Portals

发现每个位置都能互相达到等价于每个传送门都能互相达到,然后发现这些传送门互相形成了很多个环状物。

考虑每次重新排列操作的影响,因为对于四个已经互相链接的传送门操作没有意义,不讨论。

发现重新排列后,相当于将两个小环合并成了一个大环,那么可以将这些环看成点,跑一遍类似于最小生成树的东西就好了。

struct dsu {
	int fa[N << 1];
	inline void init(int R) {forn(i,1,R) fa[i] = i;}
	int fnd(int u) {return fa[u] == u ? u : fa[u] = fnd(fa[u]);}
	inline bool Mrg(int u, int v) {
		u = fnd(u), v = fnd(v);
		if(u == v) return 0;
		return fa[v] = u, 1;
	}
} O; 
int n, p[4][N], c[N];
int u[M], v[M], w[M], tot, id[M];
inline bool cmp(int A, int B) {return w[A] < w[B];}
int main() {
	Rdn(n); O.init(n << 1);
	forn(i,1,n) {
		Rdn(c[i], p[0][i], p[1][i], p[2][i], p[3][i]);
		O.Mrg(p[0][i], p[1][i]), O.Mrg(p[2][i], p[3][i]);
		u[++tot] = p[0][i], v[tot] = p[2][i], w[tot] = c[i];
		id[tot] = tot;
	}
	sort(id + 1, id + tot + 1, cmp);
	int res = 0;
	forn(i,1,n) if(O.Mrg(u[id[i]], v[id[i]])) res += w[id[i]];
	Wtn(res, '\n'); flush();
	return 0;
}

T3 - Permutation

手膜发现每次形成的东西必定是一个大三角形里面装了很多个小三角形。

发现这个 \(N\) 的数据范围就是给 \(N ^ 5\) 的东西开的,直接设出 \(f(l, i, j, k)\) 表示长度为 \(l\) ,且构造出来的最外围的三角形的三个顶点分别是 \((i, j, k)\) 的合法排列个数。

然后发现,每次操作的转移,要么是外面的点新加进来,要么是加一个里面的点。

对于外面新加进来的点,先判断点 \(p\) 是否在三角形 \((i, j, k)\) 中,这一步可以用面积法解决,然后很自然的三个转移就出来了。

对于里面加的点,状态 \(f(l - 1, i, j, k)\) 中每个排列还剩下 \(sum - l + 4\) 个在三角形 \((i, j, k)\) 中的点没有被加入,其中 \(sum\) 表示在 \((i, j, k)\) 中的所有点多个数。

所以有转移:

\[f(l, i, j, k) \leftarrow f(l - 1, i, j, p) \\ \\ f(l, i, j, k) \leftarrow f(l - 1, i, k, p) \\ \\ f(l, i, j, k) \leftarrow f(l - 1, j, k, p) \\ \\ f(l, i, j, k) \leftarrow (sum - l + 1) \times f(l - 1, i, j, k) \\ \\ \]

对于每个相同三角形,为了状态表示不重复,所以在所有状态中,将 \((i, j, k)\) 升序排序。

于是就获得了一个自带 \(\frac{1}{6}\) 常数的 \(\mathcal O (N ^ 5)\) 的做法。

Mint dp[N][N][N][N]; int n, x[N], y[N];
inline i64 Area(int a, int b, int c) {
	return labs(1ll * (x[c] - x[a]) * (y[c] - y[b]) - 1ll * (x[c] - x[b]) * (y[c] - y[a]));
}
inline bool check(int a, int b, int c, int O) {
	return Area(a, b, c) == Area(a, b, O) + Area(a, c, O) + Area(b, c, O);
}
inline void QS(int& a, int& b, int& c) {
	if(a > b) swap(a, b);
	if(a > c) swap(a, c);
	if(b > c) swap(b, c);
}
int main() {
	Rdn(n);
	forn(i,1,n) Rdn(x[i], y[i]);
	forn(i,1,n) forn(j,i + 1,n) forn(k,j + 1,n)
		dp[3][i][j][k] = Mint(6);
	forn(l,4,n) forn(i,1,n) forn(j,i + 1,n) forn(k,j + 1,n) {
		int sum = 0;
		forn(p,1,n) if(p != i && p != j && p != k && check(i, j, k, p)) {
			static int x, y, z;
			x = i, y = j, z = p; QS(x, y, z);
			dp[l][i][j][k] += dp[l - 1][x][y][z];
			x = i, y = k, z = p; QS(x, y, z);
			dp[l][i][j][k] += dp[l - 1][x][y][z];
			x = j, y = k, z = p; QS(x, y, z);
			dp[l][i][j][k] += dp[l - 1][x][y][z];
			sum ++ ;
		}
		dp[l][i][j][k] += Mint(sum - l + 4) * dp[l - 1][i][j][k];
	}
	Mint res(0);
	forn(i,1,n) forn(j,i + 1,n) forn(k,j + 1,n) res += dp[n][i][j][k];
	Wtn(res.res, '\n'); flush();
	return 0;
}

标签:pre,forn,Gold,Area,int,题解,sum,OPEN,dp
来源: https://www.cnblogs.com/Ax-Dea/p/15260152.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有