A - camel Case
题意:给定一个字符串,找到唯一存在的大写字母的位置
S是一个长度在2和100之间的字符串,由大写和小写英文字母组成。
S正好有一个大写字母。
#include<iostream>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<functional>
#define fi first
#define se second
using namespace std;
using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
const int dir[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };
const int N = 2e4 + 5;
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
string s;
cin >> s;
int cnt = 1;
for (char c : s) {
if (isupper(c)) {
cout << cnt;
break;
}
++cnt;
}
return 0;
}
B - Trimmed Mean
题意:给你一个长度为5N5N5N的数组,剔除NNN个最小值,NNN个最大值,求剩下的数的平均值
- 1≤N≤1001≤N≤1001≤N≤100
- 0≤Xi≤1000\leq X_i≤1000≤Xi≤100
#include<iostream>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<functional>
#define fi first
#define se second
using namespace std;
using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
const int dir[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };
const int N = 2e4 + 5;
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
int cnt = n;
n *= 5;
vector<int> a(n);
for (int i = 0; i < n; i++) cin >> a[i];
sort(a.begin(), a.end());
double ans = 0;
for (int i = cnt; i < n - cnt; i++) {
ans += a[i];
}
printf("%.8f", ans / (n - 2 * cnt));
return 0;
}
C - LRUD Instructions 2
题意:你在二维平面的起点(0,0)(0,0)(0,0)上,每次可以上下左右移动,给你一个字符串SSS表示移动序列
- (x+1,y)(x+1,y)(x+1,y) if the i-th character of S is
R; - (x−1,y)(x-1,y)(x−1,y) if the i-th character of S is
L; - (x,y+1)(x,y+1)(x,y+1) if the i-th character of S is
U; - (x,y−1)(x,y-1)(x,y−1) if the i-th character of S is
D,
你需要判断该移动序列有没有经过重复点的情况
1≤N≤2×1051≤N≤2×10^51≤N≤2×105
思路: 考虑数据范围小,用set模拟即可
#include<iostream>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<functional>
#define fi first
#define se second
using namespace std;
using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
const int dir[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };
const int N = 2e4 + 5;
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
set<pii> s;
int n;
cin >> n;
pii st = { 0, 0 };
s.insert(st);
bool flag = 0;
for (int i = 0; i < n; i++) {
char c;
cin >> c;
if (c == 'R') st = { st.first + 1, st.second };
if (c == 'L') st = { st.first - 1, st.second };
if (c == 'U') st = { st.first, st.second + 1};
if (c == 'D') st = { st.first, st.second - 1};
if (s.count(st)) flag = 1;
s.insert(st);
}
if (flag) cout << "Yes";
else cout << "No";
return 0;
}
D - Flip Cards
题意:给你 nnn 张牌,每张牌的正面为 A[i]A[i]A[i] ,反面为 B[i]B[i]B[i] ,初始时所有牌都在正面,你可以翻转0或任意多张牌,使得对于每一对相邻的牌,写在其正面的整数是不同的,统计该方案数并mod 998244353
- 1≤N≤2×1051\le N\le 2\times10^51≤N≤2×105
- 1≤A[i],B[i]≤1091\le A[i],B[i]\le10^91≤A[i],B[i]≤109
思路: 简单的递推dp,令dp[i][0/1]dp[i][0/1]dp[i][0/1]表示前 iii 张牌中相邻的牌均不相同的方案数,且第 iii 张牌为 A[i]/B[i]A[i]/B[i]A[i]/B[i],每次与前面一张不相同的牌转移即可
#include<iostream>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<functional>
#define fi first
#define se second
using namespace std;
using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
const int dir[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };
const int N = 2e5 + 5;
ll a[N][2], dp[N][2];
int mod = 998244353;
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
int n;
cin >> n;
dp[0][0] = 1;
for (int i = 1; i <= n; i++) cin >> a[i][0] >> a[i][1];
for (int i = 1; i <= n; i++) {
if (a[i][0] != a[i - 1][0])
dp[i][0] = (dp[i][0] + dp[i - 1][0]) % mod;
if (a[i][0] != a[i - 1][1])
dp[i][0] = (dp[i][0] + dp[i - 1][1]) % mod;
if (a[i][1] != a[i - 1][0])
dp[i][1] = (dp[i][1] + dp[i - 1][0]) % mod;
if (a[i][1] != a[i - 1][1])
dp[i][1] = (dp[i][1] + dp[i - 1][1]) % mod;
}
cout << (dp[n][0] + dp[n][1]) % mod;
return 0;
}
E - Find Permutation
题意:给定一个长度为 nnn 的排列 AAA,给你 mmm 对关系 (Xi,Yi)(X_i,Y_i)(Xi,Yi) 表示 AXi<AYiA_{X_i}<A_{Y_i}AXi<AYi,你需要判断根据这些关系能否唯一确定该排列的顺序
- 2≤N≤2×1052\le N\le 2\times 10^52≤N≤2×105
- 1≤M≤2×1051\le M\le 2\times 10^51≤M≤2×105
- 1≤Xi,Yi≤N1\le X_i,Y_i\le N1≤Xi,Yi≤N
Sample Input 1
3 2
3 1
2 3
Sample Output 1
Yes
3 1 2
We can uniquely determine that A=(3,1,2).
Sample Input 2
3 2
3 1
3 2
Sample Output 2
No
Two sequences (2,3,1) and (3,2,1) can be A.
Sample Input 3
4 6
1 2
1 2
2 3
2 3
3 4
3 4
Sample Output 3
Yes
1 2 3 4
思路: 拓扑排序即可,如果存在多个入度为0的点或者拓扑排序发现环,则无法确定该排列
#include<iostream>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<functional>
#include<stack>
#define fi first
#define se second
using namespace std;
using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
const int dir[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };
const int maxn = 2e5 + 5;
int n, m;
vector<int> e[maxn];
int degree[maxn];
int a[maxn];
stack<int> s;
bool topo() {
int sz = 0;
bool finished = true;
for (int i = 1; i <= n; i++) {
if (!degree[i]) s.push(i);
}
while (!s.empty()) {
if (s.size() > 1) finished = false;
int k = s.top();
a[sz++] = k;
s.pop();
for (int i = 0; i < e[k].size(); i++)
if (--degree[e[k][i]] == 0)
s.push(e[k][i]);
}
if (sz < n || !finished) return false;
return true;
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> m;
while (m--) {
int u, v;
cin >> u >> v;
e[u].push_back(v);
degree[v]++;
}
if (!topo()) {
cout << "No" << "\n";
}
else {
cout << "Yes" << "\n";
vector<int> ans(n + 1);
int cnt = 1;
for (int i = 0; i < n; i++) {
ans[a[i]] = cnt++;
}
for (int i = 1; i <= n; i++) cout << ans[i] << " ";
}
return 0;
}
F - Teleporter and Closed off
题意:有 NNN 个城市,给定一个N×MN\times MN×M的矩阵 SSS,若 S[i][j]=1S[i][j]=1S[i][j]=1则表示城市 iii 与 i+ji+ji+j 之间有一条有向边,边权均为 1,对于 k∈[2,N]k\in[2,N]k∈[2,N],你需要回答从城市1到城市NNN且不经过城市kkk的最短路,若不能到达则输出−1-1−1
- 3≤N≤1053\le N\le 10^53≤N≤105
- 1≤M≤101\le M\le 101≤M≤10
- M<NM<NM<N
- 如果i+j>Ni+j>Ni+j>N则S[i][j]=0S[i][j]=0S[i][j]=0
- S[i][j]∈[0,1]S[i][j]\in[0,1]S[i][j]∈[0,1]
Sample Input 1
5 2
11
01
11
10
00
Sample Output 1
2 3 2
Sample Input 2
6 3
101
001
101
000
100
000
Sample Output 2
-1 3 3 -1
思路: 本题有两个特殊之处:路径的各结点编号是递增的,MMM范围比较小。我们先正反向建图,跑两遍dijkstra\text{dijkstra}dijkstra预处理出从起点出发到各结点的最短路d1[i]d1[i]d1[i],以及从终点出发到各结点的最短路d2[i]d2[i]d2[i]。对于每次需要去除的顶点kkk,我们需要枚举每一条边(i,j)(i,j)(i,j)满足 i∈[1,k−1],j∈[k+1,N]i\in[1,k-1],j\in[k+1,N]i∈[1,k−1],j∈[k+1,N],则不经过顶点 kkk 的最短路即为
ans=mini∈[1,k−1]j∈[k+1,N]S[i][j]=1{d1[i]+d2[j]+1}
ans=\mathop{min}\limits_{\substack{i\in[1,k-1]\\j\in[k+1,N]\\S[i][j]=1}}\{d1[i]+d2[j]+1\}
ans=i∈[1,k−1]j∈[k+1,N]S[i][j]=1min{d1[i]+d2[j]+1}
由于j−i≤M,1≤M≤10j-i\le M,1\le M\le 10j−i≤M,1≤M≤10的特性,我们暴力枚举矩阵的[k−m+1,k−1][k-m+1, k-1][k−m+1,k−1]行即可
时间复杂度为:O(NM2+ElogN)O(NM^2+E\log N)O(NM2+ElogN),EEE为图的边数
#include<iostream>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<functional>
#include<stack>
#define fi first
#define se second
using namespace std;
using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
const int dir[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };
const int maxn = 1e6 + 5;
ll inf = (1ll << 50);
int n, m, s, t;
vector<vector<pii>> e1, e2;
vector<ll> d1, d2;
void dijkstra(int s, vector<vector<pii>>& e, vector<ll>& d) {
vector<bool> vis(n + 1);
priority_queue<pll> q;
q.push({ d[s] = 0, s });
while (!q.empty()) {
pll now = q.top(); q.pop();
int u = now.second;
if (vis[u]) continue;
vis[u] = 1;
for (auto[to, w] : e[u]) {
if (d[to] > d[u] + w) {
d[to] = d[u] + w;
q.push({ -d[to], to });
}
}
}
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> m;
s = 1, t = n;
e1.resize(n + 1), e2.resize(n + 1), d1.resize(n + 1, inf), d2.resize(n + 1, inf);
vector<string> g(n + 1);
for (int i = 1; i <= n; i++) {
string s;
cin >> s;
s = " " + s;
g[i] = s;
for (int j = 1; j < s.size(); j++) {
if (s[j] == '1') {
e1[i].push_back({ i + j, 1 });
e2[i + j].push_back({ i, 1 });
}
}
}
dijkstra(s, e1, d1);
dijkstra(t, e2, d2);
for (int i = 2; i <= n - 1; i++) {
ll ans = inf;
for (int j = i - 1; j >= 1 && j > i - m; j--) {
for (int k = 1; k <= m; k++) {
if (j + k > i && g[j][k] == '1')
ans = min(ans, d1[j] + d2[j + k] + 1);
}
}
if (ans == inf) cout << -1 << " ";
else cout << ans << " ";
}
return 0;
}
F题有一个加强版
https://ac.nowcoder.com/acm/problem/14293?&headNav=acm
Delete
给定一张n个点,m条边的带权有向无环图,同时给定起点S和终点T,一共有q个询问,每次询问删掉某个点和所有与它相连的边之后S到T的最短路,询问之间互相独立(即删除操作在询问结束之后会立即撤销),如果删了那个点后不存在S到T的最短路,则输出-1。
输入描述:
第一行四个正整数表示n,m,S,T,意义如题所述;
接下来m行每行三个正整数x[i],y[i],z[i],表示有一条x[i]到y[i]的有向边,权值为z[i];
第m+1行一个正整数q表示询问次数;
接下来q行每行一个正整数a[i]表示这次询问要删除点a[i]。
n,q<=105n,q <= 10^5n,q<=105
m<=2∗105m <= 2*10^5m<=2∗105
z[i]<=109z[i] <= 10^9z[i]<=109
输出描述:
q行每行一个数输出答案,如果删了这个点后不存在S到T的最短路,输出-1
输入
6 7 1 5
1 2 2
2 3 4
3 4 3
4 5 5
3 5 9
1 6 10
6 5 13
4
3
4
2
6
输出
23
15
23
14
思路
本题相较于上题,每一条边(i,j)(i,j)(i,j)没有了j−i≤Mj-i\le Mj−i≤M的限制,同时路径的结点编号也不一定递增,且每条边权重不一定为1,但大体思路相同,先正反向建图,跑两遍dijkstra\text{dijkstra}dijkstra预处理出从起点出发到各结点的最短路d1[i]d1[i]d1[i],以及从终点出发到各结点的最短路d2[i]d2[i]d2[i]。考虑拓扑序,对于删除的顶点 kkk ,一定有一条边(i,j)(i,j)(i,j)从 kkk 的左边连接到 kkk 的右边, 即满足top[i]<top[k],top[j]>top[k]top[i]<top[k], top[j]>top[k]top[i]<top[k],top[j]>top[k]。我们可以枚举所有的边(i,j)(i,j)(i,j),用 d1(s,i)+w(i,j)+dist(j,t)d1(s, i) + w(i, j) + dist(j, t)d1(s,i)+w(i,j)+dist(j,t),用线段树更新拓扑序中[top[i]+1,top[j]−1][top[i]+1, top[j]-1][top[i]+1,top[j]−1]的区间的最小值,查询时单点查询即可。
查询时有个地方需要注意,对于d1[i]=infd1[i]=infd1[i]=inf或者d2[i]=infd2[i]=infd2[i]=inf的点,删除后并不会对s→ts\rightarrow ts→t的最短路产生影响,结果仍为d1[t]d1[t]d1[t],由于它们并不在s→ts\rightarrow ts→t的路径上,所以使用拓扑序并不一定能更新到这些点

他们的拓扑序为:
| i | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 |
|---|---|---|---|---|---|---|---|---|
| id[i] | 1 | 4 | 2 | 5 | 6 | 7 | 3 | 8 |
如起点s=1s=1s=1,终点t=5t=5t=5,6和8的拓扑序比5的拓扑序更大,枚举边时不会被更新到,但删除他们的结果均为1→2→5=61\rightarrow2\rightarrow5=61→2→5=6
#include<iostream>
#include<string>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<algorithm>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<bitset>
#include<functional>
#include<stack>
#define fi first
#define se second
using namespace std;
using ll = long long;
using ld = long double;
using pii = pair<int, int>;
using pll = pair<ll, ll>;
const int dir[4][2] = { {-1, 0}, {0, 1}, {1, 0}, {0, -1} };
const int maxn = 1e6 + 5;
ll inf = (1ll << 50);
int n, m, s, t;
vector<vector<pii>> e1, e2;
vector<ll> d1, d2;
int id[maxn], fid[maxn], degree[maxn], pos;
struct tag {
ll add;
tag operator + (const tag& t) const {
return { min(add, t.add) };
}
void clear() {
add = inf;
}
};
struct Node {
int l, r;
ll val;
tag t;
}tr[4 * maxn];
void pushup(int u) {
tr[u].val = min(tr[u << 1].val, tr[u << 1 | 1].val);
}
void settag(int u, tag& t) {
tr[u].t = tr[u].t + t;
tr[u].val = min(tr[u].val, tr[u].t.add);
}
void pushdown(int u) {
settag(u << 1, tr[u].t);
settag(u << 1 | 1, tr[u].t);
tr[u].t.clear();
}
void build(int u, int l, int r) {
tr[u] = { l, r, inf, {inf} };
if (l == r) return;
int mid = (l + r) >> 1;
build(u << 1, l, mid);
build(u << 1 | 1, mid + 1, r);
pushup(u);
}
void update(int u, int l, int r, tag t) {
if (tr[u].l >= l && tr[u].r <= r) {
settag(u, t);
return;
}
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if (l <= mid) update(u << 1, l, r, t);
if (r > mid) update(u << 1 | 1, l, r, t);
pushup(u);
}
ll query(int u, int l, int r) {
if (tr[u].l >= l && tr[u].r <= r) {
// 特判不在s->t路径上的点
if (d1[fid[l]] == inf || d2[fid[l]] == inf) return d1[t];
else return tr[u].val;
}
pushdown(u);
int mid = (tr[u].l + tr[u].r) >> 1;
if (l > mid) return query(u << 1 | 1, l, r);
else if (r <= mid) return query(u << 1, l, r);
else return query(u << 1, l, r) + query(u << 1 | 1, l, r);
}
void dijkstra(int s, vector<vector<pii>>& e, vector<ll>& d) {
vector<bool> vis(n + 1);
priority_queue<pll> q;
q.push({ d[s] = 0, s });
while (!q.empty()) {
pll now = q.top(); q.pop();
int u = now.second;
if (vis[u]) continue;
vis[u] = 1;
for (auto [to, w] : e[u]) {
if (d[to] > d[u] + w) {
d[to] = d[u] + w;
q.push({ -d[to], to });
}
}
}
}
void topo() {
queue<int> q;
for (int i = 1; i <= n; i++) {
if (degree[i] == 0) {
q.push(i);
}
}
while (!q.empty()) {
int now = q.front(); q.pop();
id[now] = ++pos;
fid[pos] = now;
for (auto [to, w] : e1[now]) {
degree[to]--;
if (!degree[to]) {
q.push(to);
}
}
}
}
int main() {
ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
cin >> n >> m >> s >> t;
e1.resize(n + 1), e2.resize(n + 1), d1.resize(n + 1, inf), d2.resize(n + 1, inf);
while (m--) {
int u, v, w;
cin >> u >> v >> w;
degree[v]++;
e1[u].push_back({ v, w });
e2[v].push_back({ u, w });
}
dijkstra(s, e1, d1);
dijkstra(t, e2, d2);
topo();
build(1, 1, n);
for (int i = 1; i <= n; i++) {
for (auto [j, w] : e1[i]) {
if (id[i] != id[j] - 1 && d1[i] != inf && d2[j] != inf) {
update(1, id[i] + 1, id[j] - 1, { d1[i] + d2[j] + w });
}
}
}
int q;
cin >> q;
while (q--) {
int pos;
cin >> pos;
ll res = query(1, id[pos], id[pos]);
cout << (res == inf ? -1 : res) << "\n";
}
return 0;
}
/*
8 7 1 5
1 2 2
2 5 4
3 4 5
4 6 6
3 8 7
7 8 8
4 8 5
*/
1052

被折叠的 条评论
为什么被折叠?



