A题题意:给定n个房子及其价格,自己有B美元,求最多能买多少个房子
题解:将房子价钱排序后从小到大购买即可。
AC代码:
#include
using namespace std;
int main() {
int t;
int n;
int budgt;
cin>>t;
for (int j = 1; j <= t; j++) {
cin>>n;
cin>>budgt;
vector dp;
for (int i = 1; i <= n; i++) {
int x;
cin>>x;
dp.push_back(x);
}
sort(dp.begin(), dp.end());
int ans = 0;
for (int i = 0; i < dp.size(); i++) {
if (budgt >= dp[i]) {
budgt -= dp[i];
ans++;
}
}
printf("Case #%d: %d\n", j,ans);
}
return 0;
}
B题题意:桌子上有N堆盘子,每堆有K个盘子,每个盘子有一个观赏值,对于每一堆盘子,每次只能从上打下拿盘子,求最多拿取P个盘子能获得的总价值。
题解:动态规划,sum[i][j]为价值前缀和,即sum[i][j]表示对于第i堆盘子,拿取前j个盘子获得的总价值。dp[i][j]表示前i堆盘子中拿取j个盘子能获得的最大值。转移方程dp[i][j] = max(dp[i][j], dp[i - 1][j - l] + sum[i][l]),其中0 < i <= n,0 <= j <= p。
AC代码:
#include
using namespace std;
int sum[55][33];
int dp[55][1507];
int a[55][33];
int main() {
int t;
int n;
int k;
int p;
cin>>t;
for (int j = 1; j <= t; j++) {
cin>>n>>k>>p;
memset(dp, 0, sizeof(dp));
memset(sum, 0, sizeof(sum));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= k; j++) cin>>a[i][j];
}
for (int i = 1; i <= n; i++) {
sum[i][1] = a[i][1];
for (int j = 2; j <= k; j++) sum[i][j] = sum[i][j - 1] + a[i][j];
}
int ans = 0;
for (int i = 1; i <= k; i++) dp[1][i] = sum[1][i];
for (int i = 2; i <= n; i++) {
for (int j = 0; j <= p; j++) {
if (j > i * k) break;
for (int l = 0; l <= k; l++) {
if (j >= l) dp[i][j] = max(dp[i][j], dp[i - 1][j - l] + sum[i][l]);
}
}
}
ans = dp[n][p];
printf("Case #%d: %d\n", j,ans);
}
return 0;
}
C题题意:给定n个递增的数,然后向数组中插入k个数使得数组仍然递增,求插入后两个相邻元素差值的最小值是多少。
题解:二分最小差值,然后判断当前差值是否都达到即可。
AC代码:
#include
using namespace std;
const int maxn = 1e5 + 7;
int a[maxn];
int n;
int k;
bool check(int mid) {
int now = 0;
int last = a[1];
int p = 2;
while (p <= n) {
if (a[p] - last > mid) {
now++;
last = last + mid;
} else {
last = a[p];
p++;
}
}
return now <= k;
}
int main() {
int t;
cin>>t;
for (int j = 1; j <= t; j++) {
cin>>n>>k;
for (int i = 1; i <= n; i++) cin>>a[i];
int l = 1;
int r = 0;
int ans = 1;
for (int i = 2; i <= n; i++) r = max(a[i] - a[i - 1], r);
while (l <= r) {
int mid = (l + r) / 2;
if (check(mid)) {
r = mid - 1;
ans = mid;
}
else l = mid + 1;
}
printf("Case #%d: %d\n", j, ans);
}
return 0;
}
D题题意:给定N个只包含大写字母的字符串,将其分为P组,每组有K个字符串,P*K = N,每组的价值为最长公共前缀的长度,求所有组的最大总价值和。
题解:先将字符串按字典序排序后,dfs(i, j, k)表示第i个字符串到第j个字符串的第k位。如果i -> j中的第k位相同的字符串数大于K,说明当前字符串分为一组后能使得总价值+1,将第k位都相同的字符串截止dfs即可。
AC代码:
#include
using namespace std;
const int maxn = 1e5 + 7;
vector a;
int ans;
int n, k;
void dfs(int l, int r, int w) {
int last = l;
int sum = 1;
for (int i = l; i <= r; i++) {
if (i < r && i < n - 1 && a[i].length() > w && a[i + 1].length() > w && a[i][w] == a[i + 1][w]) {
sum++;
continue;
}
if (sum >= k) {
ans += sum / k;
dfs(last, i, w + 1);
}
last = i + 1;
sum = 1;
}
}
int main() {
int t;
scanf("%d", &t);
for (int j = 1; j <= t; j++) {
scanf("%d%d", &n, &k);
a.clear();
ans = 0;
for (int i = 1; i<= n; i++){
char pp[maxn* 20];
scanf("%s", &pp);
a.push_back(pp);
}
sort(a.begin(), a.end());
if (k == 1) {
for (int i = 0; i < n; i++) ans += a[i].length();
printf("Case #%d: %d\n", j,ans);
continue;
}
int l = 0;
int sum = 1;
for (int i = 0; i < n; i++) {
if (i < n - 1 && a[i][0] == a[i + 1][0]) {
sum++;
continue;
}
if (sum >= k) {
ans += sum / k;
dfs(l, i, 1);
}
l = i + 1;
sum = 1;
}
printf("Case #%d: %d\n", j,ans);
}
return 0;
}