T-A
问题描述
蒜头君从现在开始工作,年薪 N 万。他希望在蒜厂附近买一套 6060 平米的房子,现在价格是 200万。假设房子价格以每年百分之 K 增长,并且蒜头君未来年薪不变,且不吃不喝,不用交税,每年所得 N万全都积攒起来,问第几年能够买下这套房子?(第一年年薪 N 万,房价 200万)
Input
输入仅一行,包含两个正整数 N(10≤N≤50),K(1≤K≤20),中间用单个空格隔开。
Output
如果在第 2020 年或者之前就能买下这套房子,则输出一个整数 MM,表示最早需要在第 MM 年能买下;否则输出"Impossible"。
输出时每行末尾的多余空格,不影响答案正确性
思路
求出第i年的房价200*(1+K/100)^i与积累的积蓄i*N。因此通过一个while循环就可解决,需要注意的是就是当i大于20时跳出循环。
代码
#include <iostream>
using namespace std;
double n, k1, k, al;
double p = 200;
int main()
{
cin >> n >> k1;
k = k1 / 100;
for (int i = 1; i <= 20; i++)
{
al = n * i;
if (al >= p)
{
cout << i << endl;
return 0;
}
p = p * (1 + k);
}
cout << "Impossible" << endl;
return 0;
}
T-B
蒜头君的班级里有 n^2个同学,现在全班同学已经排列成一个 n * n 的方阵,但是老师却临时给出了一组新的列队方案为了方便列队,所以老师只关注这个方阵中同学的性别,不看具体的人是谁。这里我们用 0 表示男生,用 1 表示女生。
现在蒜头君告诉你同学们已经排好的方阵是什么样的,再告诉你老师希望的方阵是什么样的,他想知道同学们已经列好的方阵能否通过顺时针旋转变成老师希望的方阵。
1.不需要旋转则输出 0
2.顺时针旋转 90° 则输出 1
3.顺时针旋转 180° 则输出 2
4.顺时针旋转 270° 则输出 3
若不满足以上四种情况则输出 -1
若满足多种情况,则输出较小的数字
Input
第一行为一个整数 n
接下来的 n行同学们已经列好的 01方阵;
再接下来的 n行表示老师希望的的 01方阵。
Output
输出仅有一行,该行只有一个整数,如题所示。
思路
本题就是要我们求出矩阵顺时针旋转90°的公式
对应关系为:
x[i][j] = y[n-j-1][i]
具体的求解过程就不再介绍了。依次顺时针旋转矩阵90度,并记录旋转次数。如果结果矩阵与我们要求的矩阵一致,那么救输出对应的旋转次数。
代码
#include <iostream>
#include <stdio.h>
using namespace std;
int a[30][30], b[30][30], c[30][30];
int n;
bool judge()
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
if(a[i][j]!=b[i][j])
return false;
return true;
}
void convert()
{
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
c[i][j] = a[n-1-j][i];
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
a[i][j] = c[i][j];
}
int main()
{
scanf("%d", &n);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d", &a[i][j]);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
scanf("%d", &b[i][j]);
for(int i=0;i<=4;i++)
{
if(judge())
{
printf("%d\n", i);
return 0;
}
convert();
}
printf("-1\n");
return 0;
}
T-C
问题描述
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
你的任务是对给定的密文进行解密得到明文。
你需要注意的是,密文中出现的字母都是大写字母。密文中也包括非字母的字符,对这些字符不用进行解码。
Input
输入仅有一行,给出密文,密文不为空,而且其中的字符数不超过 200
Output
输出一行,即密文对应的明文。
输出时每行末尾的多余空格,不影响答案正确性
思路
需要注意的是空格也需要读入,另外对于’A’到’E’,不能直接进行减5操作,而应改为加21。此外需要注意操作的字符必须是’A’到’Z’。
代码
#include <iostream>
#include <string>
using namespace std;
int temp;
char a;
int main()
{
string s;
getline(cin, s);
for (int i = 0; i < s.size(); i++)
{
if (s[i] >= 'A' && s[i] <= 'Z')
{
temp = s[i] - 'A';
temp = (temp + 21) % 26;
a = 'A' + temp;
s[i] = a;
}
}
cout << s << endl;
}
T-C
问题描述
东东和他的女朋友(幻想的)去寿司店吃晚餐(在梦中),他发现了一个有趣的事情,这家餐厅提供的 n 个的寿司被连续的放置在桌子上 (有序),东东可以选择一段连续的寿司来吃。
东东想吃鳗鱼,但是东妹想吃金枪鱼。核 平 起 见,他们想选择一段连续的寿司(这段寿司必须满足金枪鱼的数量等于鳗鱼的数量,且前一半全是一种,后一半全是另外一种)我们用1代表鳗鱼,2代表金枪鱼。
比如,[2,2,2,1,1,1]这段序列是合法的,[1,2,1,2,1,2]是非法的。因为它不满足第二个要求。
东东希望你能帮助他找到最长的一段合法寿司,以便自己能吃饱。
Input
第一行:一个整数n(2≤n≤100000),寿司序列的长度。
第二行:n个整数(每个整数不是1就是2,意义如上所述)
Output
一个整数(代表东东可以选择的最长的一段连续的且合法的寿司)
思路
代码
#include <iostream>
#include <stdio.h>
#include <vector>
using namespace std;
vector<int> a, b;
int main()
{
int n, m, sum, t1, t2;
scanf("%d", &n);
for(int i=0;i<n;i++)
{
scanf("%d", &m);
a.push_back(m);
}
for(int i=0;i<n-1;i++)
{
sum = 1;
while(a[i]==a[i+1])
sum++, i++;
b.push_back(sum);
}
if(a[n-2]!=a[n-1])
b.push_back(1);
t1 = 0, t2 = 0;
for(int i=0;i<b.size()-1;i++)
{
t1 = min(b[i], b[i+1]);
t2 = max(t2, t1*2);
}
printf("%d", t2);
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 的程序,可根据具体金额请求机器交付现金。
注意,这个程序计算程序得出的最大现金少于或等于可以根据设备的可用票据供应有效交付的现金。
Input
程序输入来自标准输入。
输入中的每个数据集代表特定交易,
其格式为:
Cash N n1 D1 n2 D2 … nN DN
其中0 <= Cash <= 100000是所请求的现金量;
0 <= N <= 10是 纸币面额的数量;
0 <= nk <= 1000是Dk面额的可用纸币的数量;
1 <= Dk <= 1000,k = 1 … N。
输入中的数字之间可以自由出现空格。
输入数据正确。
Output
对于每组数据,程序将在下一行中将结果打印到单独一行上的标准输出中。
结果
典型的多重背包问题。使用二进制拆分转化为完全背包来解决。(主义逆序)
代码
#include <algorithm>
#include <iostream>
#include <stdio.h>
#include <string.h>
using namespace std;
const int maxn = 1e5 + 10;
const int maxl = 1e3 + 10;
int a[maxl], b[maxl], v[maxl], f[maxn], D_k, N_k, cnt;
void doo()
{
for (int i = 1; i <= N_k; i++)
scanf("%d%d", &a[i], &b[i]);
if (D_k == 0 || N_k == 0)
{
printf("0\n");
return;
}
memset(f, 0, sizeof(f));
cnt = 0;
for (int i = 1; i <= N_k; i++)
{
int t = a[i];
for (int k = 1; k <= t; k = k * 2)
{
cnt++;
v[cnt] = b[i] * k;
t = t - k;
}
if (t > 0)
{
cnt++;
v[cnt] = t * b[i];
}
}
int ans = 0;
for (int i = 1; i <= cnt; i++)
{
for (int j = D_k; j >= v[i]; j--)
{
f[j] = max(f[j], f[j - v[i]] + v[i]);
ans = max(ans, f[j]);
}
}
printf("%d\n", ans);
}
int main()
{
while (cin >> D_k >> N_k)
doo();
}
F - 选做题11-2 东东开车了
问题描述
东东开车出去泡妞(在梦中),车内提供了 n 张CD唱片,已知东东开车的时间是 n 分钟,他该如何去选择唱片去消磨这无聊的时间呢
假设:
1.CD数量不超过20张
2.没有一张CD唱片超过 N 分钟
3.每张唱片只能听一次
4.唱片的播放长度为整数
5.N 也是整数
6.我们需要找到最能消磨时间的唱片数量,并按使用顺序输出答案(必须是听完唱片,不能有唱片没听完却到了下车时间的情况发生)
Input
多组输入
每行输入第一个数字N, 代表总时间,第二个数字 M 代表有 M 张唱片,后面紧跟 M 个数字,代表每张唱片的时长 例如样例一: N=5, M=3, 第一张唱片为 1 分钟, 第二张唱片 3 分钟, 第三张 4 分钟
所有数据均满足以下条件:
N≤10000
M≤20
Output
输出所有唱片的时长和总时长,具体输出格式见样例
方法
比较简单典型的01背包问题。难点在于输出路径。
使用二维数组多记录记录,p[i][j]表示j容量的最优解是否选取了第i个物品,之后再递归到j-a[i]的容量是否选取了第i-1个物品。
#include <cstring>
#include <iostream>
using namespace std;
const int M = 1e4 + 10;
const int N = 20 + 5;
int dp[M];
int p[N][M];
int a[N];
int n, L;
void output(int i, int l)
{
if (i > 1)
output(i - 1, l - p[i][l]);
if (p[i][l])
cout << p[i][l] << " ";
}
int main()
{
while (cin >> L)
{
memset(dp, 0, sizeof(dp));
memset(p, 0, sizeof(p));
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i];
for (int i = 1; i <= n; i++)
{
for (int j = L; j >= a[i]; j--)
{
if (dp[j] <= dp[j - a[i]] + a[i])
{
dp[j] = dp[j - a[i]] + a[i];
p[i][j] = a[i];
}
}
}
output(n, L);
cout << "sum:" << dp[L] << endl;
}
}