赞
踩
前言
- 这是我第一次写7题(A~G)的ABC题解,若有写得不好或者不到位的地方请多多指教,我将万分感激,感谢大家的支持!
给定正整数
N
N
N,输出ASCII码是
N
N
N的字母。
97
≤
N
≤
122
97\le N\le 122
97≤N≤122
N N N
输出ASCII码是 N N N的字母。
注意a
对应
97
97
97,b
对应
98
98
98,……,z
对应
122
122
122。
安上小白专属转换教程:
int n = 97;
putchar(n); /* 输出:a */
putchar
函数自动转换为字符,也可以使用printf("%c", n)
效果相同int n = 97;
cout << char(n) << endl; // 输出:a
cout << n
会输出97
,需要用char
转换为字符n = 97
print(chr(n)) # 输出:a
chr
转换int n = 97;
char c = (char) n;
System.out.print(c);
var n = 97;
var c = String.fromCharCode(n);
console.log(c); // 输出:a
String.fromCharCode
再不懂你试试……
太水,直接走一发py(现场25秒AC)
print(chr(int(input())))
Takahashi的房子里有
N
N
N个食物。第
i
i
i个食物的美味度是
A
i
A_i
Ai。
其中,他不喜欢
K
K
K个食物:
B
1
,
B
2
,
…
,
B
K
B_1,B_2,\dots,B_K
B1,B2,…,BK。
已知Takahashi会从
N
N
N个食物中随机选取一个美味度最大的食物,并把它吃掉。
Takahashi是否有可能迟到不喜欢的食物?
1
≤
K
≤
N
≤
100
1\le K\le N\le 100
1≤K≤N≤100
1
≤
A
i
≤
100
1\le A_i\le 100
1≤Ai≤100
1
≤
B
i
≤
N
1\le B_i\le N
1≤Bi≤N
N
K
N~K
N K
A
1
…
A
N
A_1~\dots~A_N
A1 … AN
B
1
…
B
K
B_1~\dots~B_K
B1 … BK
如果有可能,输出Yes
;否则,输出No
。
只要有不喜欢的食物美味度最高就有可能,否则不可能。详见代码。
还是水,注意如果是 0-indexed \text{0-indexed} 0-indexed的话 B i B_i Bi要减 1 1 1
#include <cstdio> using namespace std; int a[105]; int main() { int n, k, mx = 0; scanf("%d%d", &n, &k); for(int i=0; i<n; i++) { scanf("%d", a + i); if(a[i] > mx) mx = a[i]; } while(k--) { scanf("%d", &n); if(a[--n] == mx) { puts("Yes"); return 0; } } puts("No"); return 0; }
略,请自行前往AtCoder查看。
2 ≤ N ≤ 100 2\le N\le 100 2≤N≤100
N
N
N
S
1
S_1
S1
⋮
\vdots
⋮
S
N
S_N
SN
输出答案。
令 cnt [ i ] [ j ] = ( S k [ j ] = i \text{cnt}[i][j]=(S_k[j]=i cnt[i][j]=(Sk[j]=i的个数 ) ) ),对最终变成 0 0 0- 9 9 9分别计算代价即可。详见代码。
#include <cstdio> using namespace std; int cnt[10][10]; // cnt[i][j] = number of (s[j]=i) int main() { int n; scanf("%d", &n); for(int i=0; i<n; i++) { char s[15]; scanf("%s", s); for(int j=0; j<10; j++) cnt[s[j] ^ 48][j] ++; } int ans = 1000; for(int i=0; i<10; i++) { int cur = 0; for(int j=0; j<10; j++) { int c = j + (cnt[i][j] - 1) * 10; if(c > cur) cur = c; } if(cur < ans) ans = cur; } printf("%d\n", ans); return 0; }
给定长为
N
N
N的整数序列
A
=
(
A
1
,
…
,
A
N
)
A=(A_1,\dots,A_N)
A=(A1,…,AN)。
求符合以下条件的整数对
(
i
,
j
,
k
)
(i,j,k)
(i,j,k)的个数:
3
≤
N
≤
2
×
1
0
5
3\le N\le 2\times 10^5
3≤N≤2×105
1
≤
A
i
≤
2
×
1
0
5
1\le A_i\le 2\times 10^5
1≤Ai≤2×105
N
N
N
A
1
…
A
N
A_1~\dots~A_N
A1 … AN
输出一行,即符合条件的整数对 ( i , j , k ) (i,j,k) (i,j,k)的个数。
本题主要有两种思路:
这里介绍第一种方法(第二种方法较为简单,不详细说明)。
首先易得,总共的
1
≤
i
<
j
<
k
≤
N
1\le i<j<k\le N
1≤i<j<k≤N有
C
n
3
C_n^3
Cn3种取法。
然后考虑
A
i
,
A
j
,
A
k
A_i,A_j,A_k
Ai,Aj,Ak中有重复的个数:
总时间复杂度为 O ( N + max A − min A ) \mathcal O(N+\max_A-\min_A) O(N+maxA−minA),空间复杂度为 O ( max A − min A ) \mathcal O(\max_A-\min_A) O(maxA−minA)。
#include <cstdio> #define maxn 200005 using namespace std; using LL = long long; int cnt[maxn]; inline LL C2(int n) { return n * (n - 1LL) >> 1LL; } inline LL C3(int n) { return C2(n) * (n - 2LL) / 3LL; } int main() { int n; scanf("%d", &n); for(int i=0; i<n; i++) { int a; scanf("%d", &a); cnt[a] ++; } LL ans = C3(n); for(int i=1; i<maxn; i++) if(cnt[i] > 1) { ans -= C2(cnt[i]) * (n - cnt[i]); if(cnt[i] > 2) ans -= C3(cnt[i]); } printf("%lld\n", ans); return 0; }
给定一张由
N
N
N个点和
M
M
M条边组成的简单无向图。
第
i
i
i条边长度为
C
i
C_i
Ci,同时连接点
A
i
A_i
Ai和
B
i
B_i
Bi。
求任意一颗生成树,使得从点
1
1
1到其他所有点的距离之和最小。
2
≤
N
≤
2
×
1
0
5
2\le N\le 2\times 10^5
2≤N≤2×105
N
−
1
≤
M
≤
2
×
1
0
5
N-1\le M\le 2\times 10^5
N−1≤M≤2×105
1
≤
A
i
<
B
i
≤
N
1\le A_i<B_i\le N
1≤Ai<Bi≤N
(
A
i
,
B
i
)
≠
(
A
j
,
B
j
)
(A_i,B_i)\ne(A_j,B_j)
(Ai,Bi)=(Aj,Bj)(
i
≠
j
i\ne j
i=j)
1
≤
C
i
≤
1
0
9
1\le C_i\le 10^9
1≤Ci≤109
N
M
N~M
N M
A
1
B
1
C
1
A_1~B_1~C_1
A1 B1 C1
⋮
\vdots
⋮
A
M
B
M
C
M
A_M~B_M~C_M
AM BM CM
按任意顺序输出留下来的 N − 1 N-1 N−1条边的下标,用空格隔开。
显然,在生成树中,点
1
1
1到任意点的距离肯定不少于在原图中到这个点的距离。
因此,如果两个距离相等,显然就是最优解。
此时可以证明,肯定有这样的解。使用Dijkstra
算法求最短路径的同时,记录到每个点之前的最后一条路即可。
Dijkstra的两种经典实现方式, O ( N log N + M log N ) \mathcal O(N\log N+M\log N) O(NlogN+MlogN)
priority_queue
优先队列(
182
ms
182\text{ms}
182ms)#include <cstdio> #include <queue> #define maxn 200005 #define INF 9223372036854775807LL using namespace std; using LL = long long; using pli = pair<LL, int>; struct Edge { int v, id; LL d; inline Edge(int u, int l, int i): v(u), d(l), id(i) {} }; vector<Edge> G[maxn]; LL dis[maxn]; int ans[maxn]; int main() { int n, m; scanf("%d%d", &n, &m); for(int i=1; i<=m; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); G[--a].emplace_back(--b, c, i); G[b].emplace_back(a, c, i); } priority_queue<pli, vector<pli>, greater<pli>> q; for(int i=1; i<n; i++) dis[i] = INF; q.emplace(0LL, 0); while(!q.empty()) { auto [d, v] = q.top(); q.pop(); if(dis[v] == d) for(const Edge& e: G[v]) { LL nd = d + e.d; if(nd < dis[e.v]) q.emplace(dis[e.v] = nd, e.v), ans[e.v] = e.id; } } for(int i=1; i<n; i++) printf("%d ", ans[i]); return 0; }
set
集合(
202
ms
202\text{ms}
202ms)#include <cstdio> #include <vector> #include <set> #define maxn 200005 #define INF 9223372036854775807LL using namespace std; using LL = long long; using pli = pair<LL, int>; struct Edge { int v, id; LL d; inline Edge(int u, int l, int i): v(u), d(l), id(i) {} }; vector<Edge> G[maxn]; LL dis[maxn]; int ans[maxn]; int main() { int n, m; scanf("%d%d", &n, &m); for(int i=1; i<=m; i++) { int a, b, c; scanf("%d%d%d", &a, &b, &c); G[--a].emplace_back(--b, c, i); G[b].emplace_back(a, c, i); } set<pli> s; // <distance, vertex> for(int i=1; i<n; i++) dis[i] = INF; s.emplace(0LL, 0); while(!s.empty()) { auto [d, v] = *s.begin(); s.erase(s.begin()); for(const Edge& e: G[v]) { LL nd = d + e.d; if(nd < dis[e.v]) { if(dis[e.v] < INF) s.erase(pli(dis[e.v], e.v)); s.emplace(dis[e.v] = nd, e.v); ans[e.v] = e.id; } } } for(int i=1; i<n; i++) printf("%d ", ans[i]); return 0; }
注意使用long long
。
本题翻译已经过简化,部分表示与原题不同,仅供参考,请以原题为准。
有一个的整数序列 S S S,初始只有一个元素 L L L,我们可以执行如下操作无限次:
求最小的代价,使得 A A A在 S S S中,即 A A A中每个元素的出现次数 ≤ S ~\le S ≤S中对应元素的出现次数。
2
≤
N
≤
2
×
1
0
5
2\le N\le 2\times 10^5
2≤N≤2×105
1
≤
N
≤
1
0
9
1\le N\le 10^9
1≤N≤109
A
1
+
A
2
+
⋯
+
A
N
≤
L
≤
1
0
15
A_1+A_2+\dots+A_N\le L\le 10^{15}
A1+A2+⋯+AN≤L≤1015
N
L
N~L
N L
A
1
…
A
N
A_1~\dots~A_N
A1 … AN
输出最小的代价。
本题考虑逆向思维,仔细思考后发现题目可以如下转化:
此时,显然每次合并最小的两个数即为最优方案,因此可以使用优先队列实现,总时间复杂度为 O ( N log N ) \mathcal O(N\log N) O(NlogN)。
注意使用long long
。
#include <cstdio> #include <queue> using namespace std; using LL = long long; int main() { int n; LL l; scanf("%d%lld", &n, &l); priority_queue<LL, vector<LL>, greater<LL>> q; for(int i=0; i<n; i++) { int x; scanf("%d", &x); q.push(x); l -= x; } if(l > 0) q.push(l); LL ans = 0LL; while(q.size() > 1) { LL x = q.top(); q.pop(); x += q.top(); q.pop(); ans += x; q.push(x); } printf("%lld\n", ans); return 0; }
有一颗由
N
N
N个节点
1
,
2
,
…
,
N
1,2,\dots,N
1,2,…,N组成的树,它的根节点为
1
1
1。
它的先序遍历序列是
(
P
1
,
P
2
,
…
,
P
N
)
(P_1,P_2,\dots,P_N)
(P1,P2,…,PN)。
每次搜索时,我们都会优先前往编号小的节点。
有多少种不同的树,使其符合上述条件?对
998244353
998244353
998244353取模。
2
≤
N
≤
500
2\le N\le 500
2≤N≤500
1
≤
P
i
≤
N
1\le P_i\le N
1≤Pi≤N
P
1
=
1
P_1=1
P1=1
P
1
≠
P
2
≠
…
≠
P
N
P_1\ne P_2\ne\dots\ne P_N
P1=P2=…=PN
N
N
N
P
1
…
P
N
P_1~\dots~P_N
P1 … PN
输出答案,对 998244353 998244353 998244353取模。
我们先将
P
P
P变为
0-indexed
\text{0-indexed}
0-indexed,即原来的
(
P
1
,
P
2
,
…
,
P
N
)
(P_1,P_2,\dots,P_N)
(P1,P2,…,PN)分别对应
(
A
0
,
A
1
,
…
,
A
N
−
1
)
(A_0,A_1,\dots,A_{N-1})
(A0,A1,…,AN−1)。
此时,不妨考虑区间
dp
\text{dp}
dp的思想,设
d
p
(
l
,
r
)
=
(
\mathrm{dp}(l,r)=~(
dp(l,r)= (一棵树已经去掉根节点的先序遍历为
A
l
,
A
l
+
1
,
…
,
A
r
−
1
A_l,A_{l+1},\dots,A_{r-1}
Al,Al+1,…,Ar−1的可能数
)
)
),则
d
p
(
1
,
N
)
\mathrm{dp}(1,N)
dp(1,N)即为所求。
下面考虑 d p ( l , r ) \mathrm{dp}(l,r) dp(l,r)的动态转移方程。
至此,本题已结束,时间复杂度为 O ( N 3 ) \mathcal O(N^3) O(N3)。
注意事项:
long long
再取模。#include <cstdio> #define MOD 998244353 #define maxn 505 using namespace std; using LL = long long; int p[maxn], dp[maxn][maxn]; int main() { int n; scanf("%d", &n); for(int i=0; i<n; i++) scanf("%d", p + i); for(int l=n; l>0; l--) { dp[l][l] = 1; for(int r=l+1; r<=n; r++) { dp[l][r] = dp[l + 1][r]; for(int k=l+1; k<r; k++) if(p[l] < p[k] && (dp[l][r] += LL(dp[l + 1][k]) * dp[k][r] % MOD) >= MOD) dp[l][r] -= MOD; } } printf("%d\n", dp[1][n]); return 0; }
#include <cstdio> #define MOD 998244353 #define maxn 505 using namespace std; using LL = long long; int p[maxn], dp[maxn][maxn]; int main() { int n; scanf("%d", &n); for(int i=0; i<n; i++) scanf("%d", p + i); for(int i=1; i<=n; i++) dp[i][i] = 1; for(int d=1; d<=n; d++) for(int l=1, r=d+1; r<=n; l++, r++) { dp[l][r] = dp[l + 1][r]; for(int k=l+1; k<r; k++) if(p[l] < p[k] && (dp[l][r] += LL(dp[l + 1][k]) * dp[k][r] % MOD) >= MOD) dp[l][r] -= MOD; } printf("%d\n", dp[1][n]); return 0; }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。