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

你可能感兴趣的:(20191011模拟赛)