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
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
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
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
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
#include
#include
#include
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
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;
}