1. 吃月饼
有一块月饼,是正三角形的,又被分割成了许多块小正三角形的月饼,里面有若干块被吃掉了。现在想要在这块月饼中再找一个由小正三角形月饼的正三角形月饼,而且要求面积最大的。
样例解释:
大月饼的分解情况如图,灰的表示已被吃掉的月饼,白的表示未被吃的。最大的是由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 表示),如下图。
在每一格平原地形上最多可以布置一支炮兵部队(山地上不能够部署炮兵部队);一支炮兵部队在地图上的攻击范围如图中黑色区域所示:
如果在地图中的灰色所标识的平原上部署一支炮兵部队,则图中的黑色的网格表示它能够攻击到的区域:沿横向左右各两格,沿纵向上下各两格。
图上其它白色网格均攻击不到。从图上可见炮兵的攻击范围不受地形的影响。
现在,将军们规划如何部署炮兵部队,在防止误伤的前提下(保证任何两支炮兵部队之间不能互相攻击,即任何一支炮兵部队都不在其他支炮兵部队的攻击范围内),在整个地图区域内最多能够摆放多少我军的炮兵部队。
输入
第一行包含两个由空格分割开的正整数,分别表示 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
N∗N的网格地图上部署他们的炮兵部队。一个
N
∗
N
N*N
N∗N的地图由
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;
}