HGOI 20200716

海星,一天比一天简单
开题顺序2-3-1,跟ZJOI一样

T1 交错匹配(cross)

这个题稍微复杂些

首先看到图片容易想到二分图匹配,但由于题目中的交叉限制,是不大可能(?)用匈牙利或网络流做的

在仔细观察这个题就是最大字串匹配加了一个限制,数据也是给 (O(N^2)) 出的

考虑如何把这个信息处理掉

由于每个左斜匹配只会与一个右斜匹配对应,

为了最大化答案,每个 (a) 应当和更接近的 (b) 匹配, 每个 (b) 应当和更接近的 (a) 匹配

这样的话我们就可以模仿最大字串的做法

(f[i][j]) 表示 (a) 串匹配到第 (i) 位,(b) 串匹配到第 (j) 位 的最大匹配数量

枚举 (a) 串的每个元素 (i),记录每个数出现的最前位置

然后枚举 (b) 串的每个元素 (j)

由于 (i) 以后的元素还未经处理,因此只会出现

i'     i 
* .. . x ..
j'   j
x .. *

这样的情况

因此我们就只需要记录下 (b)数组中与 (a[i]) 相等的最靠近 (i) 的元素编号即可 (代码中为 (lst)

转移方程:
(f[i][j] = max(f[i][j], f[s[b[j]] - 1][lst - 1] + 2))

(f[i][j]) 的初始值是 (max(f[i - 1][j], f[i][j - 1]))

答案 (f[n][m])

如果没有那个 (1 v 1) 的限制应该怎么做啊。

数组开小太搞笑

#include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define siz(a) (int)a.size()
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second

const int N = 1010 ;

int n, m, lst ;
int a[N], b[N], s[N] ;
int f[N][N] ; // f[i][j] 表示a串匹配到第i位,b串匹配到第j位 

signed main() {
	freopen("cross.in", "r", stdin) ;
	freopen("cross.out", "w", stdout) ;
	scanf("%d%d", &n, &m) ;
	rep(i, 1, n) scanf("%d", &a[i]) ;
	rep(i, 1, m) scanf("%d", &b[i]) ;
	memset(s, 0x3f, sizeof(s)) ;
	rep(i, 1, n) {
		lst = 0 ;
		rep(j, 1, m) {
			f[i][j] = max(f[i - 1][j], f[i][j - 1]) ;
			if (a[i] != b[j]) {
				if (lst && s[b[j]] < i) f[i][j] = max(f[i][j], f[s[b[j]] - 1][lst - 1] + 2) ;
			} else {
				lst = j ;
			}
		}
		s[a[i]] = i ;
	} 
	printf("%d
", f[n][m]) ;
	return 0 ;
}
/*
12 11 
1 2 3 3 2 4 1 5 1 3 5 10
3 1 2 3 2 4 12 1 5 5 3 
----
4 4 
1 1 3 3 
1 1 3 3  
*/

T2 奶牛晒衣服(dry)

送分题

贪心
对于当前时间最长的衣服进行烘干即可

#include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define siz(a) (int)a.size()
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second

const int N = 100010 ;

int n, a, b ;
priority_queue <int> q ;

signed main() {
	freopen("dry.in", "r", stdin) ;
	freopen("dry.out", "w", stdout) ;
	scanf("%d%d%d", &n, &a, &b) ;
	rep(i, 1, n) {
		int t ; scanf("%d", &t) ;
		q.push(t) ;
	}
	int ans = 0, sum = 0 ;
	while (!q.empty()) {
		int x = q.top() ; q.pop() ;
	//	cout << x << endl ;
		if (x <= sum) {
			printf("%d
", ans) ;
			return 0 ;
		}
		x -= b ;
		sum += a ;
		ans++ ;
		q.push(x) ;
	}
	printf("%d
", ans) ;
	return 0 ;
}
/*
3 2 1 
1 2 3 
*/

T3 奶牛排队(flip/tahort)

对于两头奶牛 (i,j(i<j)), 如果 (a[i]<a[j]) 那么右端点选 (j) 必然比 (i) 更优

这样的话其实 (i) 作为右端点是不可能的了

但依然可以作为左端点

考虑枚举左端点

依次加入每头奶牛至队列中(栈也阔以)

如果加入的奶牛与前一头满足上述关系就把他们合并掉

合并的时候要考虑一下前一头奶牛能够到达的左端点能不能更新当前的信息

然后每次对答案进行更新

如果 (ans=1) 即只有一头奶牛那么是不合法的,(ans) 赋为 (0)

比如(~5~4~3~2~1)

#include <bits/stdc++.h>
using namespace std;

#define rep(i, a, b) for (int i = a; i <= b; i++)
#define per(i, a, b) for (int i = a; i >= b; i--)
#define siz(a) (int)a.size()
#define pb push_back
#define mp make_pair
#define ll long long
#define fi first
#define se second

const int N = 100010 ;

struct range {
	int lp, lh, rp, rh ;
} ;

range sta[N] ;

int n, ans, top ;
int a[N] ;

signed main() {
	freopen("tahort.in", "r", stdin) ;
	freopen("tahort.out", "w", stdout) ;
	scanf("%d", &n) ;
	rep(i, 1, n) scanf("%d", &a[i]) ;
	ans = 0, top = 0 ;
	rep(i, 1, n) {
		top++ ;
		sta[top].lh = sta[top].rh = a[i] ;
		sta[top].lp = sta[top].rp = i ;
		while (sta[top].rh > sta[top - 1].rh && top > 1) {
			if (sta[top].lh > sta[top - 1].lh) {
				sta[top].lh = sta[top - 1].lh ;
				sta[top].lp = sta[top - 1].lp ;
			}
			sta[top - 1] = sta[top] ;
			top-- ;
		}
		ans = max(ans, sta[top].rp - sta[top].lp + 1) ;
	}
	if (ans == 1) ans = 0 ;
	printf("%d
", ans) ;
	return 0 ;
}
/*
5 
1 2 3 4 1
*/ 

原文地址:https://www.cnblogs.com/harryhqg/p/13323342.html