蓝桥杯冲冲冲~
回顾
蓝桥杯每日练习(算式900,谈判幸运数,123)
蓝桥杯每日练习(神奇算式,缩位求和,积木大赛)
蓝桥杯每日练习(猴子分香蕉,等差数列,平方序列,倍数问题)
蓝桥杯每日练习(纯质数(筛法的应用),最少砝码,灌溉)
蓝桥杯每日练习(年龄巧合,纸牌三角形,取球游戏)
今天继续蓝桥杯每日练习~ 今天的题目最主要可以练习的呢,就是最长公共子序列模型和字符串哈希。字符串哈希是一个很常用的工具。虽然他单独被用来做考题的概率很小,但是他是一个工具,被一道题当作一个中间步骤来用的可能性是很大的。最长公共子序列是一个常见模型,换句话说,你掌握了这个模型就相当于会了很多题目。我是学习算法的小菜鸡,每天练习几个知识点,我们国赛见~
模拟 |
国王将金币作为工资,发放给忠诚的骑士。第一天,骑士收到一枚金币;之后两天(第二天和第三天),每天收到两枚金币;之后三天(第四、五、六天),每天收到三枚金币;之后四天(第七、八、九、十天),每天收到四枚金币…;这种工资发放模式会一直这样延续下去:当连续 N 天每天收到 N 枚金币后,骑士会在之后的连续 N+1 天里,每天收到 N+1 枚金币。
请计算在前 K 天里,骑士一共获得了多少金币。
原题传送门
才1e4的数据那你还在想什么?模拟呀!依据题意循环就可以了。
#include
using namespace std;
int main() {
int k;
cin >> k;
int flag = 1, ans = 0;
while (k) {
for (int i = 0; i < flag; i++) {
ans += flag,k--;
if (!k) break;
}
flag++;
}
cout << ans << endl;
}
一般来说,一个正整数可以拆分成若干个正整数的和。
例如,1=1,10=1+2+3+4 等。对于正整数 n 的一种特定拆分,我们称它为“优秀的”,当且仅当在这种拆分下,n 被分解为了若干个不同的 2 的正整数次幂。注意,一个数 x 能被表示成 2 的正整数次幂,当且仅当 x 能通过正整数个 2 相乘在一起得到。
例如, 10 = 8 + 2 = 2 3 + 2 1 10=8+2=2^3+2^1 10=8+2=23+21
是一个优秀的拆分。但是, 7 = 4 + 2 + 1 = 2 2 + 2 1 + 2 0 7=4+2+1=2^2+2^1+2^0 7=4+2+1=22+21+20
就不是一个优秀的拆分,因为 1 不是 2 的正整数次幂。
现在,给定正整数 n,你需要判断这个数的所有拆分中,是否存在优秀的拆分。若存在,请你给出具体的拆分方案。
原题传送门
二进制拆分 |
因为拆分的方式的二的幂,所以我们自然的想到了二进制。考虑倒是二的正整数次幂,换句话说就是不可以是 2 0 2^0 20,所以奇数一定是无解的,因为奇数拆分成二的幂以后一定包含一个 2 0 2^0 20。然后对于偶数,我们就二进制枚举一下,二进制位上是1就输出2的位数次方。
然后我们在二进制拆分的时候可以用一下lowbit,lowbit(x) = x & -x,他可以返回二进制表示最后一个1以及它后面的0,也就是拆分成二进制以后的最小数。感觉这个东西还是比较重要的,因为理解lowbit函数是学习树状数组的基础。
#include
#include
using namespace std;
int n;
vector<int>num;
int main() {
cin >> n;
if (n & 1) cout << -1 << endl;
else {
while (n) {
num.push_back(n & -n);
n -= n & -n;
}
for (int i = num.size() - 1; i >= 0; i--) cout << num[i] << ' ';
}
}
X星的坦克战车很奇怪,它必须交替地穿越正能量辐射区和负能量辐射区才能保持正常运转,否则将报废。
某坦克需要从A区到B区去(A,B区本身是安全区,没有正能量或负能量特征),怎样走才能路径最短?
已知的地图是一个方阵,上面用字母标出了A,B区,其它区都标了正号或负号分别表示正负能量辐射区。
例如:
A + - + -
- + - - +
- + + + -
+ - + - +
B + - + -
坦克车只能水平或垂直方向上移动到相邻的区。
原题传送门
bfs |
求的是最短路,我们第一反应是bfs。这道题有一个限制,就是说相邻两步的能量状态不能一样,所以加一个特判就是说不相等才能转移就可以了。
#include
#include
#include
using namespace std;
typedef pair<int, int>PII;
const int N = 110;
char mp[N][N];
int g[N][N], n, b[N][N];
PII st, ed;
int dx[] = { 1,0,-1,0 };
int dy[] = { 0,1,0,-1 };
void find() {
queue<PII>qu;
memset(g, 0x3f, sizeof g);
g[st.first][st.second] = 0;
b[st.first][st.second] = 1;
qu.push(st);
while (qu.size()) {
PII v = qu.front();
qu.pop();
for (int i = 0; i < 4; i++) {
int x = dx[i] + v.first;
int y = dy[i] + v.second;
if (x >= 0 && x < n && y >= 0 && y < n && mp[x][y] != mp[v.first][v.second] && !b[x][y]) {
g[x][y] = min(g[x][y], g[v.first][v.second] + 1);
b[x][y] = 1;
qu.push({ x,y });
}
}
}
}
int main() {
cin >> n;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
cin >> mp[i][j];
if (mp[i][j] == 'A') st = { i,j };
if (mp[i][j] == 'B') ed = { i,j };
}
}
find();
cout << g[ed.first][ed.second] << endl;
}
L 星球上的生物由蛋蓝质组成,每一种蛋蓝质由一类称为蓝肽的物资首尾连接成一条长链后折叠而成。
生物学家小乔正在研究 L 星球上的蛋蓝质。她拿到两个蛋蓝质的蓝肽序列,想通过这两条蓝肽序列的共同特点来分析两种蛋蓝质的相似性。
具体的,一个蓝肽可以使用 1 至 5 个英文字母表示,其中第一个字母大写,后面的字母小写。一个蛋蓝质的蓝肽序列可以用蓝肽的表示顺序拼接而成。
在一条蓝肽序列中,如果选取其中的一些位置,把这些位置的蓝肽取出,并按照它们在原序列中的位置摆放,则称为这条蓝肽的一个子序列。蓝肽的子序列不一定在原序列中是连续的,中间可能间隔着一些未被取出的蓝肽。
如果第一条蓝肽序列可以取出一个子序列与第二条蓝肽序列中取出的某个子序列相等,则称为一个公共蓝肽子序列。
给定两条蓝肽序列,找出他们最长的那个公共蓝肽子序列的长度。
原题传送门
哈希与动态规划 |
题目废话有点多哈。题目说了个什么事儿呢?就是说一个以大写字母大头并且后面全是小写字母的子串称为一个肽链,求有多少个在顺序保持不变的情况下最多能从两个字符串中同时选出多少个肽链。
读完题我们知道要把一个肽链看作是一个元素,所以我们很自然的想到了把字符串映射成一个整数。那么用什么方法呢?我们最常用的当然就是字符串哈希的方法了。字符串哈希是什么我们待会儿说,现在只需要知道字符串哈希以后可以把肽链(子字符串)映射成整数然后存在一个数组里。
然后呢?然后就是说我们要在两个整数数组中找到最长的公共子序列。这样就是我们很熟悉的最长公共子序列的问题了(不熟悉也没关系后面有说明)。
字符串哈希
就是一种把字符串映射成整数的算法。
这个问题是一个明显要用到dp来解决的一个问题。
d p [ i ] [ j ] dp[i][j] dp[i][j]表示在第一个字符串的 i i i位以前和第二个字符串的 j j j位以前最长公共子序列的长度。我们思考方式呢就是看最后一位是否相同。如果相同,那么直接用前一个状态加一就可以了。如果不同呢我们就可以分以下是谁不在最长公共子序列里面。但是我们来向一个问题: f [ i − 1 ] [ j ] f[i-1][j] f[i−1][j]真的是不包含 a [ i ] a[i] a[i]包含 b [ j ] b[j] b[j]的最长公共子序列吗? f [ i − 1 ] [ j ] f[i−1][j] f[i−1][j] 表示的是在 a a a的前 i − 1 i-1 i−1个字母中出现,并且在b的前j个字母中的最长公共子序列,此时 b [ j ] b[j] b[j]不一定出现。但是我们仍可以用 f [ i − 1 ] [ j ] f[i−1][j] f[i−1][j]来表示,原因就在于条件给定的情况被包含在 f [ i − 1 ] [ j ] f[i−1][j] f[i−1][j]中,即条件的情况是 f [ i − 1 ] [ j ] f[i−1][j] f[i−1][j]子集,而求的是 m a x max max,所以对结果不影响。
#include
#include
using namespace std;
typedef unsigned long long ULL;
const int N = 1010, P = 13331;
int dp[N][N], idx_a, idx_b;
string ch1, ch2;
ULL a[N], b[N], res;
int id(char c) {
return c - 'A' + 1;
}
void init() {
ch1 += ' ', ch2 += ' ';
for (int i = 0; i < ch1.size(); i++) {
if (i && ch1[i] <= 'Z') a[++idx_a] = res, res = id(ch1[i]);
else res = res * P + id(ch1[i]);
}
res = 0;
for (int i = 0; i < ch2.size(); i++) {
if (i && ch2[i] <= 'Z') b[++idx_b] = res, res = id(ch2[i]);
else res = res * P + id(ch2[i]);
}
}
int main()
{
cin >> ch1 >> ch2;
init();
for (int i = 1; i <=idx_a; i++)
{
for (int j = 1; j <=idx_b; j++)
{
dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
if (a[i] == b[j]) dp[i][j] = max(dp[i][j], dp[i - 1][j - 1] + 1);
}
}
cout << dp[idx_a][idx_b];
}