Belted Rooms (CodeForces - 1428B)
题意:给定n条边连接n个点形成一个环,有单向边和双向边,求有多少个点是可达的(即从该点出发回最终能回到该点)
思路:考虑如果所有边都是方向相同的单向边(或用双向边代替)那么n个点都是可达的,否则如果出现两条方向不同的单向边则只需考虑双向边的条数,所有连接了双向边的点就是可达的点,统计即可
代码:
#include <iostream>
#include <cstring>
using namespace std;
int main() {
int t;
scanf("%d", &t);
while (t--) {
bool flag = true;
int n, ans = 0;
string s;
cin >> n >> s;
char c;
for (int i = 0; i < n; i++)
if (s[i] != '-') {
c = s[i];
break;
}
for (int i = 0; i < n; i++) {
if (s[i] == '-') {
ans += 2;
if (i > 0 && s[i - 1] == '-')
ans--;
}
if (s[i] != c && s[i] != '-')
flag = false;
}
if (s[0] == '-' && s[n - 1] == '-')
ans--;
if (flag)
printf("%d\n", n);
else
printf("%d\n", ans);
}
return 0;
}
Program (CodeForces - 1473D)
题意:给出一串由 ‘+’ 与 ‘-’ 构成的字符串,初始值为0,‘+’代表+1,‘-’代表-1,求去掉中间任意一段(l~r)后,剩下的前缀与后缀组合可产生多少不同的数
思路:每次+1与-1生成的数都是相隔为1的连续整数,只需求出前缀与后缀组合后所得数据的极差,但因为是多组数据查询,暴力会超时,所以先预处理一遍前缀与后缀,利用前缀和求解即可 (参考https://blog.csdn.net/tomjobs/article/details/112723795)
代码:
#include <iostream>
#include <cstring>
using namespace std;
const int N = 2e5 + 5;
char s[N];
int pre[N], pre_min[N], pre_max[N];
int suf[N], suf_min[N], suf_max[N];
int main() {
int t;
scanf("%d", &t);
while (t--) {
int n, m, ans = 1;
scanf("%d%d", &n, &m);
scanf("%s", s + 1);
for (int i = 1; i <= n; i++) {
int k = (s[i] == '+' ? 1 : -1);
pre[i] = pre[i - 1] + k;
//求以i为终点的最小前缀和
pre_min[i] = min(pre_min[i - 1], pre[i]);
//求以i为终点的最大前缀和
pre_max[i] = max(pre_max[i - 1], pre[i]);
}
for (int i = 1; i <= n; i++)
printf("%d %d %d\n", pre[i], pre_min[i], pre_max[i]);
system("pause");
suf[n + 1] = suf_min[n + 1] = suf_max[n + 1] = 0;
for (int i = n; i >= 1; i--) {
int k = (s[i] == '+' ? 1 : -1);
suf[i] = suf[i + 1] + k;
//求以i为起点的最小前缀和
suf_min[i] = min(0, suf_min[i + 1] + k);
//求以i为起点的最大前缀和
suf_max[i] = max(0, suf_max[i + 1] + k);
}
while (m--) {
int l, r;
scanf("%d%d", &l, &r);
//记录以l-1为终点的前缀部分可达到的范围
int maxn = max(0, pre_max[l - 1]);
int minn = min(0, pre_min[l - 1]);
//后缀在前缀的基础上进行加减
int k = pre[l - 1];
//记录以r+1的起点的前缀部分可达到的范围
maxn = max(maxn, suf_max[r + 1] + k);
minn = min(minn, suf_min[r + 1] + k);
//答案为去掉中间段后前缀与后缀的极差
printf("%d\n", maxn - minn + 1);
}
}
return 0;
}