2022-5-20 吃月饼(something wrong), 数塔取数问题, 制铁棒, 子段统计, 炮兵阵地

1. 吃月饼

有一块月饼,是正三角形的,又被分割成了许多块小正三角形的月饼,里面有若干块被吃掉了。现在想要在这块月饼中再找一个由小正三角形月饼的正三角形月饼,而且要求面积最大的。

样例解释:

img

大月饼的分解情况如图,灰的表示已被吃掉的月饼,白的表示未被吃的。最大的是由9个小月饼组成的(黑色粗线标记)。

输入

单组测试数据。
第一行给出一个整数n (1 <= n <= 100),表示三角形月饼的高度。
接下来n行,用#, -表示该行三角形月饼的状态,#表示已经被吃掉的,-表示未被吃掉的。
从第一行到最后一行每行的字符的数目总是奇数个,并且是从2*n-1到1递减的。

输出

输出一个整数,表示找到的最大的月饼中包含的小三角形个数。

输入样例

5
#-##----#
-----#-
---#-
-#-
-

输出样例

9

代码 (something wrong)

#include<bits/stdc++.h>

#define N 105
#pragma GCC optimize(2)
using namespace std;
int a[N][N], b[N][N], dpA[N][N], dpB[N][N];

int main() {
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    string s;
    for (int i = 0; i < n; ++i) {
        cin >> s;
        for (int j = 0; j < (s.size() + 1 >> 1); j++) {
            if (s[2 * j] == '-') a[i][j] = 1;
            if (2 * j + 1 < s.size() && s[2 * j + 1] == '-') b[i][j] = 1;
        }
    }
    int ans = 0;
    for (int i = 0, prev1, prev2; i < n; ++i) {
        for (int j = 0; j < n - i; j++) {
            if (a[i][j] == 1) {
                prev1 = i > 0 ? dpA[i - 1][j] : 0;
                prev2 = i > 0 ? dpA[i - 1][j + 1] : 0;
                dpA[i][j] = min(prev1, prev2) * (i > 0 && b[i - 1][j] == 1) + 1;
                ans = max(ans, dpA[i][j]);
            }
        }
        for (int j = 0; j < n - i; j++) {
            if (b[i][j] == 1) {
                prev1 = j > 0 ? dpB[i][j - 1] : 0;
                prev2 = i > 0 ? dpB[i - 1][j] : 0;
                dpB[i][j] = min(prev1, prev2) * (a[i][j] == 1) + 1;
                ans = max(ans, dpB[i][j]);
            }
        }
    }
    cout << ans * ans;
    return 0;
}

2. 数塔取数问题

一个高度为N的由正整数组成的三角形,从上走到下,求经过的数字和的最大值。

每次只能走到下一层相邻的数上,例如从第3层的6向下走,只能走到第4层的2或9上。

5

8 4

3 6 9

7 2 9 5

例子中的最优方案是:5 + 8 + 6 + 9 = 28

输入

第1行:N,N为数塔的高度。(2 <= N <= 500)
第2 - N + 1行:每行包括1层数塔的数字,第2行1个数,第3行2个数......第k+1行k个数。数与数之间用空格分隔(0 <= A[i] <= 10^5) 。

输出

输出最大值

输入样例

4
5
8 4
3 6 9
7 2 9 5

输出样例

28

代码

#include<bits/stdc++.h>

#define N 505
#pragma GCC optimize(2)
using namespace std;
using ull = unsigned long long;
ull a[N][N];

int main() {
    ios::sync_with_stdio(false);
    int n;
    cin >> n;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j <= i; ++j) {
            cin >> a[i][j];
        }
    }
    for (int i = 1; i < n; ++i) {
        for (int j = 0; j <= i; ++j) {
            a[i][j] += max(j > 0 ? a[i - 1][j - 1] : 0, a[i - 1][j]);
        }
    }
    cout << *max_element(a[n - 1], a[n - 1] + n);
    return 0;
}

3. 制铁棒

工厂里面,有n根待加工的铁棒,长度以米为单位,精确到小数点后两位(即厘米),现在市场上需求量是m根相同长度的铁棒。现在厂长想把这n根铁棒进行切割,切割的时候要精确到厘米,比如说,原来铁棒是1.00米的,那么可以切成0.50和0.50的,但是不能切成0.499和0.501的。并且不能将两根铁棒拼成一根铁棒。现在厂长想知道切出来的m根铁棒最长能有多长。

输入

单组测试数据。
第一行给出两个整数n(1 <= n<= 10000)和m(1 <= m< = 10000)。
接下来n行给出原始铁棒的长度L[1],L[2],L[3],...,L[n] ,(1<=L[i]<=100,000)。以米为单位,精确到小数点后两位。

输出

输出一个小数表示答案,精确到小数点后两位。

输入样例

4 11
8.02
7.43
4.57
5.39

输出样例

2.00

代码

#include<bits/stdc++.h>

#define N 10005
#pragma GCC optimize(2)
using namespace std;
int a[N];
int n, m, maxLength = numeric_limits<int>::min();

bool check(int length) {
    int cnt = 0;
    for (int i = 0; i < n; ++i) { cnt += a[i] / length; }
    return cnt >= m;
}

int main() {
    ios::sync_with_stdio(false);
    cin >> n >> m;
    double val;
    for (int i = 0; i < n; ++i) {
        cin >> val;
        a[i] = val * 100;
        maxLength = max(maxLength, a[i]);
    }
    int lo = 1, hi = maxLength + 1;
    while (lo < hi) {
        int mi = lo + ((hi - lo) >> 1);
        check(mi) ? lo = mi + 1 : hi = mi;
    }
    cout << fixed << setprecision(2) << (lo - 1) / 100.0 << endl;
    return 0;
}

4. 子段统计

给定一个字符串S,只由k种小写字母组成。现在给定一个长度L,要求统计一下S有多少种不同的长度为L的子段(S中连续的几个字符)。

输入

第一行两个整数L和k。(L>=1,1<=k<=26,k^L<=2*10^7)
第二行一个字符串S。(1<=|S|<=1000000)

输出

输出一个整数表示答案。

输入样例

1 2
ababab

输出样例

2

代码

#include<bits/stdc++.h>

#pragma GCC optimize(2)
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    unordered_set<string> uset;
    int l, k;
    cin >> l >> k;
    string s;
    cin >> s;
    for (int i = 0; i + l <= s.size(); i++) {
        uset.insert(s.substr(i, l));
    }
    cout << uset.size() << endl;

    return 0;
}

5. 炮兵阵地 v1

司令部的将军们打算在 N × M N\times M N×M 的网格地图上部署他们的炮兵部队。

一个 N × M N\times M N×M 的地图由 N N N M M M 列组成,地图的每一格可能是山地(用 H \texttt{H} H 表示),也可能是平原(用 P \texttt{P} P 表示),如下图。

在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:

img

如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。

图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。

现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。

输入

第一行包含两个由空格分割开的正整数,分别表示 N 和 M。
接下来的 N 行,每一行含有连续的 M 个字符,按顺序表示地图中每一行的数据。

输出

一行一个整数,表示最多能摆放的炮兵部队的数量。

输入样例

5 4
PHPP
PPHH
PPPP
PHPP
PHHP

输出样例

6

代码

#include<bits/stdc++.h>

#pragma GCC optimize(2)
using namespace std;
int n, m, ans, dp[(1 << 10)][(1 << 10)][3], a[105], Sum[(1 << 10)];
char x;

int main() {
    ios::sync_with_stdio(false);
    cin >> n >> m;
    for (int i = 0; i < n; i++)
        for (int j = 0; j < m; j++)
            cin >> x, a[i] <<= 1, a[i] += (x == 'H' ? 1 : 0);
    for (int i = 0; i < (1 << m); i++)
        Sum[i] = __builtin_popcount(i);
    for (int S = 0; S < (1 << m); S++)
        if (!(S & a[0] || (S & (S << 1)) || (S & (S << 2))))
            dp[0][S][0] = Sum[S];
    for (int L = 0; L < (1 << m); L++) {
        if (L & a[0] || (L & (L << 1)) || (L & (L << 2))) continue;
        for (int S = 0; S < (1 << m); S++)
            if (!(L & S || S & a[1] || (S & (S << 1)) || (S & (S << 2))))
                dp[L][S][1] = Sum[S] + Sum[L];
    }
    for (int i = 2; i < n; i++)
        for (int L = 0; L < (1 << m); L++) {
            if (L & a[i - 1] || (L & (L << 1)) || (L & (L << 2))) continue;
            for (int S = 0; S < (1 << m); S++) {
                if (L & S || S & a[i] || (S & (S << 1)) || (S & (S << 2))) continue;
                for (int FL = 0; FL < (1 << m); FL++) {
                    if (FL & L || FL & S || FL & a[i - 2] || (FL & (FL << 1)) || (FL & (FL << 2))) continue;
                    dp[L][S][i % 3] = max(dp[L][S][i % 3], dp[FL][L][(i - 1) % 3] + Sum[S]);
                }
            }
        }
    for (int L = 0; L < (1 << m); L++)
        for (int S = 0; S < (1 << m); S++)
            ans = max(ans, dp[L][S][(n - 1) % 3]); //结束状态可以是最后一行的任何状态
    cout << ans;
    return 0;
}

6. 炮兵阵地 v2

司令部的将军们打算在 N ∗ N N*N NN的网格地图上部署他们的炮兵部队。一个 N ∗ N N*N NN的地图由 N N N N N N列组成,地图的每一格可能是山地(用"X"表示),也可能是平原(用"."表示)。在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围是它所在位置的对应的行和列,但是大炮打出去之后如果被山地阻挡 了,那么攻击范围就到那块山地。

现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。

输入

单组测试数据。 第一行有一个整数N(1<=N<=4)。 接下来N行,每行有N个字符(只有两种字符:'.' 表示平原, 'X'表示山地)。

输出

一行一个整数,表示最多能摆放的炮兵部队的数量。

输入样例

4
.X..
....
XX..
....

输出样例

5

代码

#include<bits/stdc++.h>

#define N 5
#pragma GCC optimize(2)
using namespace std;
int n, ans = 0;
bool grid[N][N];
bool used[N][N];

bool check(int x, int y) {
    int i = x;
    while (++i < n && grid[i][y]) {
        if (used[i][y]) return false;
    }
    i = x;
    while (--i >= 0 && grid[i][y]) {
        if (used[i][y]) return false;
    }
    i = y;
    while (++i < n && grid[x][i]) {
        if (used[x][i]) return false;
    }
    i = y;
    while (--i >= 0 && grid[x][i]) {
        if (used[x][i]) return false;
    }
    return true;
}

void dfs(int cur) {
    ans = max(ans, cur);
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            if (grid[i][j] && !used[i][j] && check(i, j)) {
                used[i][j] = true;
                dfs(cur + 1);
                used[i][j] = false;
            }
        }
    }
}


int main() {
    ios::sync_with_stdio(false);
    cin >> n;
    char ch;
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < n; ++j) {
            cin >> ch;
            if (ch == '.') grid[i][j] = true;
        }
    }
    dfs(0);
    cout << ans;
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值