A. Two Towers
思路:将第二个串从右往左接到第一个串上,然后遍历第一个串,并记录存在连续两个相同颜色block的个数与是否存在连续3个相同颜色的block,如果连续2个相同个数大于一或者存在连续三个相同block,输出NO。
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int N;
cin >> N;
while (N--){
int n, m;
string a, b;
cin >> n >> m >> a >> b;
int tag = 0, len = 1, cnt = 0;
a = a + string(b.rbegin(), b.rend());
for (int i = 1; i < a.size(); ++i){
if (a[i] == a[i - 1]) len += 1;
else len = 1;
if (len == 2){cnt += 1;}
if (cnt > 1 || len == 3) {tag = 1; break;}
}
cout << (tag == 0 ? "YES" : "NO") << endl;
}
return 0;
}
B. Ideal Point
思路:对所有给出的区间扫描,如果K在区间内,则用map将区间内所有出现的point频率加一,如果k不在该区间内,则直接跳过。最后遍历一遍mapp,如果存在出现频率大于等于k出现频率的数,则输出NO,否则输出YES。需要注意的是当mapp为空时,则直接输出NO,因为区间数不为空,所以一定有point频率大于k。
#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;
int main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int N;
cin >> N;
while (N--){
int n, k;
cin >> n >> k;
vector<vector<int>> a(n, vector<int> (2));
map<int, int> mapp;
for (int i = 0; i < n; ++i){
cin >> a[i][0] >> a[i][1];
if (a[i][0] <= k && k <= a[i][1]){
int R = a[i][1], L = a[i][0];
while (L <= R){mapp[L] += 1; L += 1;}
}
}
int tag = 0;
for(auto x : mapp){
if ((x.second >= mapp[k] && x.first != k)) { tag = 1; break;}
}
if (mapp[k] == 0) tag = 1;
cout << (tag == 0 ? "YES\n" : "NO\n");
}
return 0;
}
C. Tea Tasting
思路:本次VP最经典的开拓思路题。
对于每杯茶被喝完与否,需要找出第几个人刚好喝不完它,那么这个人后面那个就可以喝完这杯茶,于是在扫描输入时保存b的前缀数组。然后遍历数组a,对于每个ai找出一个k值,从i~k每个人都喝了bj,然后再判断茶是否有剩,如果有剩且k<n,则把多余的茶加到b[k+1]身上。
到目前为止的关键点是找到第k个人,可以用二分,也可以用low_bound函数。这里采用倍增查找。
查找到k以后,需要保存区间,对于区间[i, k]中每个人都喝了bj(i <=j <= k),需要保存信息,在最后输出时直接用该信息*bj+该位置多余的茶即可。这里采用差分数组,如果i~k每个人都喝了一次,那么d[i] += 1, d[k + 1] -= 1(如果k < n的话)
#include <iostream>
#include <vector>
#include <string>
#include <map>
using namespace std;
int main(){
ios::sync_with_stdio(false), cin.tie(nullptr);
int N;
cin >> N;
while (N--){
int n;
cin >> n;
vector<long long int> a(n + 1), b(n + 1), r(n + 1, 0), s(n + 1, 0), d(n + 1, 0);
for (int i = 1; i <= n; ++i){
cin >> a[i];
}
for (int i = 1; i <= n; ++i){
cin >> b[i];
s[i] += s[i - 1] + b[i];
}
for (int i = 1; i <= n; ++i){
int k = i - 1, p = 1, sum = 0;
while(p){
if (k + p > n) {p /= 2; continue;}
if (sum + s[k + p] - s[k] <= a[i]){
sum += s[k + p] - s[k];
k += p;
p *= 2;
}
else{
p /= 2;
}
}
d[i] += 1;
if (k < n) d[k + 1] -= 1;
if (a[i] - sum > 0 && k < n) r[k + 1] += min(a[i] - sum, b[k + 1]);
}
for (int i = 1; i <= n; ++i){
d[i] += d[i - 1];
cout << r[i] + d[i] * b[i] << " \n"[i == n];
}
}
return 0;
}
总结:这个题目的关键点在于找到前缀和的位置以后,如何保存区间的信息,因为可能对于每杯茶来说,都需要保存一个区间的信息,如果每次保存都从左端点到右端点扫描一遍会运行超时,于是想到了差分数组。对于保存方法而言,还可以应用树状数组将区间内的值加1。(树状数组,待完成23.2.22)