题目连接: Homecoming
题目:
题目太长了, 在这里就不再复制了, 大概分析一下就是一个找连续相同字符的问题.
解题思路:
这个题的字符串来表示车站, 只有A和B两种车站. 如果在A类车站上车, 那么途径的所有A车站(期间不能有B车站)我们都可以选择下车, 如果当我们遇到B车站时, 只能选择下车. B类车站上车同理.
如题中举例: 对于串"AABBBAB", 我们从1开始标记, 到7为止.
如果我们从位置1上车, 那么我们最远可以坐到位置3, 我们也可以选择在位置2下车.
如果我们从位置2上车, 那么我们只能坐到位置3就下车.
如果我们从位置3上车, 那么我们最远可以坐到位置6, 但是我们也可以选择在4, 5位置下车.
其余情况同理.
题目中涉及到上A类车需要花费a元, 而B类车需要花费b元,而我们只有p元, 因此我们每次都应该坐的尽可能远, 减少倒车次数.
我们自然是希望能从位置1上车, 一直坐到终点的, 但是由于涉及到可能钱不够的问题, 因此我们可以考虑:
①从终点出发, 看看往回坐能坐到哪里.
②假设我们从位置1开始做, 每次上下车记录区间的花费, 最后倒着相加所有的花费, 直到得到满足题意的最小值为止.
思路分析1: 倒着跑(定下车点, 找上车点):
如果倒着跑, 我们细细分析, 会发现不能单纯的认为我们是从终点出发往起点跑.
假设我们从A类车站上车, 经历数个A类车站后到一个B类车站下车, 如: AAAAAB, 但是如果我们单纯的倒着跑, 我们认为自己从B车站上车, 但是只坐一站车, 即到下标为5的A车站就下车了, 显然我们模拟的情况是错误的.
但是如果我们经过分析, 其实我们会发现坐车大致上只有两种情况:
①我们是从同类车站上下车(到了终点)
②我们是从不同类车站上下车.
例如: AAAABBBB, 我们从A类车站(位置1)上车, 到B类车站(位置5)下车, 然后再从位置5坐到终点.
这个例子中: 第一次坐车就属于情况1, 第二次就属于情况2.
所以思路一倒着跑的难点在于: 找到真正的上车点, 至于下车点, 因为我们是倒着跑的, 所以下车点是我们的定点. 且我们知道初始的下车点就是终点, 后续的下车点是我们上一次找到的上车点.
倒着跑AC代码:
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAXN = 1E5 + 10;
int a, b, p;
int findon(char* s) {
char* op = &s[strlen(s) - 1]; //表示下车点, 默认是终点位置
while (true) {
char* ptr = op - 1; bool flag = 0; //flag表示遇到了不同类车站
if (*ptr == '#') break;
/* 找到真正的上车点 */
if (*ptr != *op) flag = 1; //说明他前面的是不同类车站, 则op为下车点
//不同类车站, 要找到最初的不同类位置 情况二
while (*ptr != *op && flag && *ptr != '#') ptr--;
//同类车站, 要找到最初同类的位置 情况一
while (*ptr == *op && !flag && *ptr != '#') ptr--;
ptr++;
const int cost = *ptr == 'A' ? a : b;
if (p - cost >= 0) p -= cost;
else break;
op = ptr;
}
return op - s;
}
int main(void)
{
int t; cin >> t;
while (t--) {
scanf("%d %d %d", &a, &b, &p);
char s[MAXN]; cin >> s + 1;
s[0] = '#'; //作为开始标志
if (a > p && b > p) { cout << strlen(s) - 1 << endl; continue; }
cout << findon(s) << endl;
}
return 0;
}
思路分析2: 正着跑(定上车点, 找下车点):
如果你明白了倒着跑的思路, 正着跑相对而言要容易很多, 因为他没有拧着逻辑, 我们哪里上车, 哪里下车也不需要分情况, 与事实情况是相同的. 在这里就不多赘述了.
#include <bits/stdc++.h>
typedef long long ll;
using namespace std;
const int MAXN = 1E5 + 10;
int num[MAXN]; //记录开销
int index[MAXN]; //记录下车点
int main(void)
{
int t; cin >> t;
while (t--) {
int a, b, p;
scanf("%d %d %d", &a, &b, &p);
char s[MAXN]; cin >> s + 1; s[0] = '5'; //这里如果从s[1]开始读入, 建议把s[0]随便初始化一下, 否则要WA
if (a > p && b > p) { cout << strlen(s) - 1 << endl; continue; }
char* op = s + 1; //表示当前所处的位置
int cou = 0; //区间数目下标
do {
const int cost = *op == 'A' ? a : b; //当前位置上车花费是a还是b
char* ptr = op + 1; //为了找到下车点
if (*ptr == '\0') break;
while (*ptr == *op && *ptr != '\0') ptr++;
num[++cou] = cost; //记录当前车站所需的花费
index[cou] = ptr - s; //记录下车位置 至于为什么记录下车点, 可以结合后面的for循环思考
if (*ptr == '\0') index[cou]--; //到串尾了, 真正下车点--
op = ptr; //让本次下车点作为下一次的上车点
} while (*op != '\0');
int res = -1;
for (int i = cou; i >= 1; --i) {
if (p - num[i] >= 0) p -= num[i];
else { res = index[i]; break; } //这趟车做不起了, 我们应该从这趟车的下车点上车
}
if (res == -1) res = 1; //说明可以从初始位置开始坐.
cout << res << endl;
}
return 0;
}
最近高产, 前一阵子太懒了, 冲冲冲!