A - 必做题11-1
问题描述
蒜头君从现在开始工作,年薪 N 万。他希望在蒜厂附近买一套 60 平米的房子,现在价格是 200 万。假设房子价格以每年百分之 K 增长,并且蒜头君未来年薪不变且不吃不喝,不用交税,每年所得 N万全都积攒起来,第几年能够买下这套房子?(第一年年薪 N 万,房价 200 万)
解题思路
遍历计算20年内每一年的房价和年薪
代码
#include <iostream>
using namespace std;
int main(){
int N, K;
cin >> N >> K;
N *= 10000;
int i;
bool flag = false;
int price = 2000000;
int salary = N;
for(i = 2; i <= 20; ++i){
price += price * K / 100;
salary += N;
if(salary >= price){
flag = true;
break;
}
}
if(flag) cout << i;
else cout << "Impossible";
return 0;
}
B - 必做题11-2
问题描述
蒜头君的班级里有 n*n 个同学,现在全班同学已经排列成一个 n∗n 的方阵,但是老师却临时给出了一组新的列队方案
为了方便列队,所以老师只关注这个方阵中同学的性别,不看具体的人是谁
这里我们用 0 表示男生,用 1 表示女生
现在蒜头君告诉你同学们已经排好的方阵是什么样的,再告诉你老师希望的方阵是什么样的
他想知道同学们已经列好的方阵能否通过顺时针旋转变成老师希望的方阵
不需要旋转则输出 0
顺时针旋转 90° 则输出 1
顺时针旋转 180° 则输出 2
顺时针旋转 270° 则输出 3
若不满足以上四种情况则输出 −1
若满足多种情况,则输出较小的数字
解题思路
方阵的逆时针旋转:先将方阵的行头尾对调,再转置
最后只需对每一个方阵判断旋转3次即可
代码
#include <iostream>
#include <algorithm>
using namespace std;
int n;
int x[25][25];
int y[25][25];
bool judge(){
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j)
if(x[i][j] != y[i][j])
return false;
return true;
}
void reverse(){
for(int i = 0; i < n / 2; ++i)
for(int j = 0; j < n; ++j)
swap(x[n-1-i][j], x[i][j]);
for(int i = 0; i < n; ++i)
for(int j = 0; j < i; ++j)
swap(x[i][j], x[j][i]);
}
int main(){
cin >> n;
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j)
cin >> x[i][j];
for(int i = 0; i < n; ++i)
for(int j = 0; j < n; ++j)
cin >> y[i][j];
if(judge()) {
cout << 0;
return 0;
}
for(int i = 1; i <= 3; ++i){
reverse();
if(judge()){
cout << i;
return 0;
}
}
cout << -1;
return 0;
}
C - 必做题11-3
问题描述
Julius Caesar 曾经使用过一种很简单的密码。对于明文中的每个字符,将它用它字母表中后 5 位对应的字符来代替,这样就得到了密文。比如字符’A’用’F’来代替。如下是密文和明文中字符的对应关系。
密文
A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
明文
V W X Y Z A B C D E F G H I J K L M N O P Q R S T U
你的任务是对给定的密文进行解密得到明文。
你需要注意的是,密文中出现的字母都是大写字母。密文中也包括非字母的字符,对这些字符不用进行解码。
解题思路
直接将字符串的每个字符减5,若小于A再加上26
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
char str[205];
char ans[205];
int main(){
gets(str);
int len = strlen(str);
for(int i = 0; i < len; i++){
if(str[i] >= 'A' && str[i] <= 'Z'){
if(str[i] - 5 >= 'A')
ans[i] = str[i] - 5;
else
ans[i] = str[i] - 5 + 26;
}else ans[i] = str[i];
}
cout << ans;
return 0;
}
D - 必做题11-4
问题描述
东东和他的女朋友(幻想的)去寿司店吃晚餐(在梦中),他发现了一个有趣的事情,这家餐厅提供的 n 个的寿司被连续的放置在桌子上 (有序),东东可以选择一段连续的寿司来吃
东东想吃鳗鱼,但是东妹想吃金枪鱼。核 平 起 见,他们想选择一段连续的寿司(这段寿司必须满足金枪鱼的数量等于鳗鱼的数量,且前一半全是一种,后一半全是另外一种)我们用1代表鳗鱼,2代表金枪鱼。
比如,[2,2,2,1,1,1]这段序列是合法的,[1,2,1,2,1,2]是非法的。因为它不满足第二个要求。
东东希望你能帮助他找到最长的一段合法寿司,以便自己能吃饱。
解题思路
读入时记录每一段连续的1和2的数量,每次出现新一段时计算当前的合法长度(1和2数量的最小值)。直到结束。
注意:新一段出现时,例如新出现1, 2的个数不变。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <string>
using namespace std;
int cnt[3];
int maxx = 0;
int main(){
int n, last;
cin >> n;
cin >> last;
cnt[last]++;
for(int i = 1; i < n; ++i){
int temp;
cin >> temp;
if(temp == last || cnt[temp] == 0)
cnt[temp]++;
else{
maxx = max(min(cnt[2], cnt[1]), maxx);
cnt[temp] = 1;
}
last = temp;
}
maxx = max(min(cnt[2], cnt[1]), maxx);
cout << maxx * 2;
return 0;
}
E - 选做题11-1 东东与 ATM
问题描述
一家银行计划安装一台用于提取现金的机器。
机器能够按要求的现金量发送适当的账单。
机器使用正好N种不同的面额钞票,例如D_k,k = 1,2,…,N,并且对于每种面额D_k,机器都有n_k张钞票。
例如,
N = 3,
n_1 = 10,D_1 = 100,
n_2 = 4,D_2 = 50,
n_3 = 5,D_3 = 10
表示机器有10张面额为100的钞票、4张面额为50的钞票、5张面额为10的钞票。
东东在写一个 ATM 的程序,可根据具体金额请求机器交付现金。
注意,这个程序计算程序得出的最大现金少于或等于可以根据设备的可用票据供应有效交付的现金。
解题思路
一道多重背包问题,我们将面额作为物品的价值和重量。
可以进行二进制拆分来降低时间复杂度。在二进制拆分之后就转换成了01背包问题。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int num[15];
int value[15];
int w[100005];
int dp[100005];
int main(){
int cash;
while(cin >> cash){
int n;
cin >> n;
for(int i = 1; i <= n; i++)
cin >> num[i] >> value[i];
memset(dp, 0, sizeof(dp));
int cnt = 0;
for(int i = 1; i <= n; i++){
int t = num[i];
for(int k = 1; k <= t; k <<= 1){
cnt++;
w[cnt] = k * value[i];
t -= k;
}
if(t > 0){
cnt++;
w[cnt] = t * value[i];
}
}
for(int i = 1; i <= cnt; i++){
for(int j = cash; j >= w[i]; j--){
dp[j] = max(dp[j], dp[j-w[i]] + w[i]);
}
}
cout << dp[cash] << endl;
}
return 0;
}
F - 选做题11-2 东东开车了
问题描述
东东开车出去泡妞(在梦中),车内提供了 n 张CD唱片,已知东东开车的时间是 n 分钟,他该如何去选择唱片去消磨这无聊的时间呢
假设:
CD数量不超过20张
没有一张CD唱片超过 N 分钟
每张唱片只能听一次
唱片的播放长度为整数
N 也是整数
我们需要找到最能消磨时间的唱片数量,并按使用顺序输出答案(必须是听完唱片,不能有唱片没听完却到了下车时间的情况发生)
本题是 Special Judge
解题思路
这道题也是一个01背包问题,但是由于要输出过程,所以多了一个回溯路径的过程。
回溯过程的实现就是考虑当前dp[x][y],如果dp[x][y]=dp[x-1][y],那就说明没有选择第x个物品,回溯x-1, y。如果dp[x][y]=dp[x-1][y-w[i]]+v[i],那么就说明选择了第x件物品,回溯x-1, y-w[i]。
代码
#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int w[25];
bool ans[25];
int dp[25][10005];
int main(){
int N;
while(cin >> N){
int M;
cin >> M;
for(int i = 1; i <= M; i++)
cin >> w[i];
for(int i = 1; i <= N; i++) dp[0][i] = 0;
for(int i = 1; i <= M; i++){
for(int j = 1; j <= N; j++){
dp[i][j] = dp[i - 1][j];
if(j - w[i] >= 0)
dp[i][j] = max(dp[i][j], dp[i - 1][j - w[i]] + w[i]);
}
}
int temp = N;
for(int i = M; i >= 1; i--){
if(dp[i][temp] != dp[i - 1][temp]){
ans[i] = true;
temp -= w[i];
}
else
ans[i] = false;
}
for(int i = 1; i <= M; i++)
if(ans[i])
cout << w[i]<< " ";
cout << "sum:" << dp[M][N] << endl;
}
return 0;
}