前言
- 这是我第一次写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);
与C++、Python类似,需要转换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
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
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
然后考虑 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
#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
( 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
#include
#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
#include
#include
#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; //
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
#include
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
#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
#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;
}