20191011模拟赛

T1

题目大意

给定一个长方体的体积\(v\),确定其长宽高\(a,b,c\)使得其长方体的表面积最小。

思路

根据均值不等式:

\(a+b+c \geq 3 \times^3 \sqrt{abc}\)

代入\(2ab, 2bc, 2ac\),即可得到\(ab+bc+ac \geq 6 \times^3 \sqrt{v^2}\),当且仅当\(a=b=c\)时成立。

我们发现这个右边的式子不能直接进行计算,考虑牛顿迭代或暴力枚举。

但是\(a=b=c\)这个条件不一定能满足,因为题目限制\(a,b,c \in \mathbb{Z}\)。所以我们应该使\(a,b,c\)三者尽量靠近。

故可以通过枚举\(a,b\),表达出\(c\),统计即可。

复杂度为\(O(V^{\frac{2}{3}})\)

代码

#include <bits/stdc++.h>
const int INF = 2147483646;
typedef int intt;
#define int long long
using namespace std;
int v, res, ans = INF;
int calc(int a, int b, int c) { return ((a * b) << 1) + ((b * c) << 1) + ((a * c) << 1); }
intt main() {
	cin >> v;
	for(int i = 1; i * i * i <= v; i++) {
		if(v % i != 0)
			continue;
		res = calc(i, sqrt(v / i), sqrt(v / i));
		if(res > ans)
			continue;
		for(int j = 1; j * j <= (v / i); j++) {
			if((v / i) % j != 0)
				continue;
			ans = min(ans, calc(i, j, (v / i) / j));
		}
	}
	cout << ans << endl;
	return 0;
}

牛顿迭代版:

#include <bits/stdc++.h>
const int lim = 100;
typedef long long ll;
using namespace std;
long double x, v;
int main() {
	cin >> v;
	v *= v;
	x = 10;
	for(int i = 1; i <= lim; i++)
		x = x - (x * x * x - v) / (3 * x * x);
	cout << 6 * x << endl;
	return 0;
}

T2

题目大意

给定一个字符串,计算出所有互不相交的回文子串对的个数。

思路

\(90pts:\)处理出所有的回文子串的\(l,r\),然后按左端点,右端点排序,枚举每个区间,二分出第一个互不相交的区间,累加其及其之后的答案即可。复杂度为\(O(n^3 + p \times logn)\),其中\(p\)为回文区间总数。(ps:\(n^3\)是指我之前的回文序列的判断与统计,十分暴力...)

\(100pts:\)首先优化回文序列的寻找过程。枚举每一个点,然后递归扩展左右,然后使用树状数组维护前缀和,最后枚举查询,查询到是区间右端点比当前区间左端点小的个数,累加即可。

代码

\(90pts:\)

#include <bits/stdc++.h>
const int MAXN = 2050;
using namespace std;
char s[MAXN];
int len, num, ans;
struct node {
	int l, r;
	bool operator < (const node &a) const {
		return a.l == l ? a.r > r : a.l > l;
	}
}a[200000000];
bool check(int x, int y) {
	for(int i = x, j = y; i <= j; i++, j--) {
		if(s[i] != s[j])
			return false;
	}
	return true;
}
bool check1(int x, int y) { return a[x].l > a[y].r; }
int main() {
	cin >> s + 1;
	len = strlen(s + 1);
	for(int i = 1; i <= len; i++) {
		for(int j = i; j <= len; j++) {
			if(check(i, j))
				a[++num] = (node){i, j};
		}
	}
	sort(a + 1, a + num + 1);
	for(int i = 1; i <= num; i++) {
		int l = i + 1, r = num, res = 0;
		while(l <= r) {
			int mid = (l + r) >> 1;
			if(check1(mid, i)) {
				res = mid;
				r = mid - 1;
			}
			else
				l = mid + 1;
		}
		if(res != 0)
			ans += (num - res + 1);
	}
	cout << ans << endl;
	return 0;
}

\(100pts:\)

#include <bits/stdc++.h>
const int MAXN = 2050;
typedef int intt;
#define int long long
using namespace std;
char s[MAXN];
int len, num, ans, c[MAXN];
struct node {
	int l, r;
}a[20000000];
int lowbit(int x) { return x & (-x); }
void add(int x) {
	while(x <= len) {
		c[x]++;
		x += lowbit(x);
	}
}
int query(int x) {
	int res = 0;
	while(x > 0) {
		res += c[x];
		x -= lowbit(x);
	}
	return res;
}
void solve(int l, int r) {
	if(l == 0 || r == len + 1)
		return ;
	a[++num] = (node){l, r};
	add(r);
	if(s[l - 1] == s[r + 1])
		solve(l - 1, r + 1);
}
intt main() {
	cin >> s + 1;
	len = strlen(s + 1);
	for(int i = 1; i <= len; i++) {
		solve(i, i);
		if(s[i] == s[i + 1])
			solve(i, i + 1);
	}
	for(int i = 1; i <= num; i++)
		ans += query(a[i].l - 1);
	cout << ans << endl;
	return 0;
}

T3

题目大意

给定两个升序序列\(A,B\),当\(A[i]-x \leq B[j] \leq A[i]+y\)时则可以将\(A[i]\)\(B[j]\)匹配。求最大匹配数。

思路

\(50pts:\)\(dp\),设\(f[i][j]\)表示\(A\)中前\(i\)个数和\(B\)中前\(j\)个数的最大匹配数。直接简单的转移即可,复杂度为\(O(n^2)\)

\(100pts:\)由于升序,且区间长度一定,则可以进行贪心的选取,即尽可能让每一个点和一个右端点尽量靠左的区间进行匹配,尽可能最大的利用区间,让剩下的点有更多的机会去匹配。实现只需要用两个指针即可。复杂度为\(O(n)\)

代码

\(50pts:\)

#include <cstdio>
#include <cctype>
#include <cstring>
#include <iostream>
const int MAXN = 1050;
using namespace std;
int n, m, x, y, a[MAXN], b[MAXN], f[MAXN][MAXN];
int main() {
	cin >> n >> m >> x >> y;
	for(int i = 1; i <= n; i++)
		cin >> a[i];
	for(int i = 1; i <= m; i++)
		cin >> b[i];
	for(int i = 1; i <= n; i++) {
		for(int j = 1; j <= m; j++) {
			if(a[i] - x <= b[j] && a[i] + y >= b[j])
				f[i][j] = max(f[i][j], f[i - 1][j - 1] + 1);
			else
				f[i][j] = max(f[i - 1][j - 1], max(f[i - 1][j], f[i][j - 1]));
		}
	}
	cout << f[n][m] << endl;
	return 0;
}

\(100pts:\)

#include <bits/stdc++.h>
const int MAXN = 100050;
using namespace std;
struct node {
	int x, y;
}g[MAXN];
int n, m, x, y, c, p1 = 1, p2 = 1, ans, f[MAXN];
bool flag;
int main() {
	cin >> n >> m >> x >> y;
	for(int i = 1; i <= n; i++) {
		cin >> c;
		g[i].x = c - x;
		g[i].y = c + y;
	}
	for(int i = 1; i <= m; i++)
		cin >> f[i];
	while(p1 <= n && p2 <= m) {
		if(f[p2] >= g[p1].x && f[p2] <= g[p1].y) {
			ans++;
			p1++;
			p2++;
		}
		else if(f[p2] > g[p1].y)
			p1++;
		else if(f[p2] < g[p1].x)
			p2++; 
	}
	cout << ans << endl;
	return 0;
}
posted @ 2019-10-12 20:00  BeyondLimits  阅读(151)  评论(1编辑  收藏  举报