前言
- 这是我第一次写7题(A~G)的ABC题解,若有写得不好或者不到位的地方请多多指教,我将万分感激,感谢大家的支持!
给定正整数,输出ASCII码是的字母。
输出ASCII码是的字母。
注意a
对应,b
对应,……,z
对应。
安上小白专属转换教程:
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的房子里有个食物。第个食物的美味度是。
其中,他不喜欢个食物:。
已知Takahashi会从个食物中随机选取一个美味度最大的食物,并把它吃掉。
Takahashi是否有可能迟到不喜欢的食物?
如果有可能,输出Yes
;否则,输出No
。
只要有不喜欢的食物美味度最高就有可能,否则不可能。详见代码。
还是水,注意如果是的话要减
#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查看。
输出答案。
令的个数,对最终变成-分别计算代价即可。详见代码。
#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;
}
给定长为的整数序列。
求符合以下条件的整数对的个数:
输出一行,即符合条件的整数对的个数。
本题主要有两种思路:
这里介绍第一种方法(第二种方法较为简单,不详细说明)。
首先易得,总共的有种取法。
然后考虑中有重复的个数:
总时间复杂度为,空间复杂度为。
#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;
}
给定一张由个点和条边组成的简单无向图。
第条边长度为,同时连接点和。
求任意一颗生成树,使得从点到其他所有点的距离之和最小。
()
按任意顺序输出留下来的条边的下标,用空格隔开。
显然,在生成树中,点到任意点的距离肯定不少于在原图中到这个点的距离。
因此,如果两个距离相等,显然就是最优解。
此时可以证明,肯定有这样的解。使用Dijkstra
算法求最短路径的同时,记录到每个点之前的最后一条路即可。
Dijkstra的两种经典实现方式,
priority_queue
优先队列()#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
集合()#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
。
本题翻译已经过简化,部分表示与原题不同,仅供参考,请以原题为准。
有一个的整数序列,初始只有一个元素,我们可以执行如下操作无限次:
求最小的代价,使得在中,即中每个元素的出现次数中对应元素的出现次数。
输出最小的代价。
本题考虑逆向思维,仔细思考后发现题目可以如下转化:
此时,显然每次合并最小的两个数即为最优方案,因此可以使用优先队列实现,总时间复杂度为。
注意使用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;
}
有一颗由个节点组成的树,它的根节点为。
它的先序遍历序列是。
每次搜索时,我们都会优先前往编号小的节点。
有多少种不同的树,使其符合上述条件?对取模。
输出答案,对取模。
我们先将变为,即原来的分别对应。
此时,不妨考虑区间的思想,设一棵树已经去掉根节点的先序遍历为的可能数,则即为所求。
下面考虑的动态转移方程。
易得,此时初始化为。
至此,本题已结束,时间复杂度为。
注意事项:
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;
}