Codeforces Round 479 (Div. 3)
比赛链接
A. Wrong Subtraction
给一个数n,俩操作执行k次:
- 个位不为0就减1
- 个位为0就除10
直接模拟,代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,k;cin>>n>>k;
while(k--){
if(n%10!=0) n--;
else n/=10;
}
cout<<n;
return 0;
}
B. Two-gram
给个字符串找字符对(无要求),使得该字符对在串中出现次数最大
先预处理出所有的字符对,再到串中找出现次数,暴力比较每一个字符对出现次数,代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n;cin>>n;
string s;
vector<string> a(n);
for(auto& c:s) cin>>c;
for(int i=0;i+1<n;i++){
a[i]+=s[i];
a[i]+=s[i+1];
}
int mx=0;
string ma;
for(int i=0;i<n-1;i++){
int cnt=0;
for(int j=0;j<n-1;j++){
if(a[i]==a[j]) cnt++;
if(cnt>mx){
mx=cnt;
ma=a[j];
}
}
}
cout<<ma;
return 0;
}
C. Less or Equal
给一个n长数组a,寻找一个数x使得数组中只有k个数大于或等于这个数
先排序,再考虑特殊情况
特判较多
- 对数组排序之后判断k和k+1位置是否相等(相等则在该处有两次大于等于x)
- k>n(找不全)
- k=0时,若a[0]=1,则找不到一个x使k=0(即必有一数大于x),若a[0]!=1则x=1(比a[0]小都行)
代码:
#include<bits/stdc++.h>
using namespace std;
int main(){
int n,k;cin>>n>>k;
vector<int> a(n);
for(auto& aa:a) cin>>aa;
sort(a.begin(),a.end());
if(a[k-1]==a[k]||k>n||(k==0&&a[0]==1)) cout<<"-1";
else if(k==0) cout<<"1";
else cout<<a[k-1];
return 0;
}
D. Divide by three, multiply by two
给一个数组,由原本数组打乱,找到原数组
原数组是一个由一个数x经历n-1次操作变成的n长数组a,操作为:
- x分三份(即除3)
- x乘2
乱序的序列,我们需要找出它们被依次书写的顺序,使得每个数都可以通过上述操作从前一个数得到 由于最终的顺序是一个单链,我们可以将数字看作一个有向图,其中边表示可以进行的转换(除以 3 或乘以 2)我们需要找到这个链的起点(即 最终的最大数或者最小数)。
通过 DFS依次构造这个链。
解法思路
建图:
遍历所有数字,对于每对数字 (a[i], a[j]):
如果 a[i] * 2 =a[j],建立一条 i → j 的边。
如果 a[i] / 3 =a[j] 且 a[i] % 3 ==0,建立 i → j 的边。
- 找到起点:链的起点只能是某个 没有前驱的节点,即没有其它数字可以通过乘 2 或除 3 得到它。
- 构造正确的顺序:从起点出发,沿着构造的路径(按照规则)依次寻找下一个数,直到遍历所有数。
最后以O(n)时间解决 代码如下:
#include<bits/stdc++.h>
using namespace std;
using ll=long long;
int main(){
int n;cin>>n;
vector<ll> a(n);
unordered_map<ll,int> p;//数与索引
unordered_map<ll,int> ind;//数与入度
for(int i=0;i<n;i++){
cin>>a[i];
p[a[i]]=i;
ind[a[i]]=0;
}
//邻接表
unordered_map<ll,vector<ll>> ne;
for(int i=0;i<n;i++){
ll tmp=a[i];
if(p.count(tmp*2)){
ne[tmp].push_back(tmp * 2);
ind[tmp*2]++;
}
if(tmp%3==0&&p.count(tmp/3)){
ne[tmp].push_back(tmp / 3);
ind[tmp/3]++;
}
}
//找入度为0的点
ll start=-1;
for(ll& aa:a){
if(ind[aa]==0){
start=aa;
break;
}
}
//顺着表输出
for(ll i=start,cnt=0;cnt<n;cnt++) {
cout<<i<<' ';
if (!ne[i].empty()) {
i = ne[i][0]; // 确保从邻接表中取出下一个节点
}
}
cout<<'\n';
return 0;
}
E. Cyclic Components
给定了一个无向图,要求计算出图中所有的 环形联通分量 的数量。图的一个联通分量是一个环形联通分量,当且仅当该分量包含的每个节点的度数都为 2,并且所有的边能构成一个闭环
环形联通分量的定义
一个联通分量是 环,当且仅当:
- 该分量的所有节点的度数都为 2(每个节点都正好与两个节点相连)
- 该分量的所有节点和边可以构成一个环
解题思路
- 通过 DFS 遍历图,找出所有的连通分量
- 对每个连通分量,检查所有节点的度数是否均为 2
- 如果是环,则计数
代码:
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> g(n + 1);// 邻接表
vector<int> de(n + 1, 0);// 存度数
vector<int> vi(n + 1, 0);// 标记节点
// 构建图,统计每个节点的度数
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
g[u].push_back(v);
g[v].push_back(u);
de[u]++;
de[v]++;
}
int cnt = 0;
//DFS
auto dfs = [&](int x, vector<int>& com, auto&& dfs_ref) -> void {
vi[x] = 1;
com.push_back(x);
for (auto& nx : g[x]) {
if (!vi[nx]) {
dfs_ref(nx, com, dfs_ref);
}
}
};
// 遍历进行DFS
for (int i = 1; i <= n; i++) {
if (!vi[i]) {
vector<int> com;
dfs(i, com, dfs);
// 检查是否为环
bool ishuan = true;
for (int nd : com) {
if (de[nd] != 2) {
ishuan = false;
break;
}
}
if (ishuan) {
cnt++;
}
}
}
cout << cnt << endl;
return 0;
}
F. Consecutive Subsequence
给定的数组中选择一个最长的递增连续子序列。这个子序列应该是按顺序的连续整数(比如 [x, x+1, x+2, ..., x+k-1])。我们需要输出这个子序列的长度以及对应的数组索引
解题思路
- 动态规划的思想:我们可以使用一个map来记录每个数能形成的最大递增连续子序列的长度。具体来说,对于数组中的每个元素 a[i],如果 a[i] - 1 这个数字已经出现过,那么 a[i] 可以接在 a[i] - 1 后面形成一个新的连续子序列。因此,我们可以更新 a[i] 所能形成的最大子序列长度为 f[a[i] - 1] + 1
- 回溯得到答案: 一旦我们找到了最长的递增连续子序列的长度,就可以从数组的末尾开始回溯,找到该子序列的索引
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n + 1);
map<int, int> f; // 用来存储每个数值的最大递增子序列长度
vector<int> ans; // 存储最终的索引
int mxn = 0, mx = 0; // mxn为最大子序列长度,mx为对应的数字
for (auto& aa:a) cin >> aa;
// 动态规划计算每个数字的最大递增子序列长度
for (int i = 1; i <= n; i++) {
f[a[i]] = f[a[i] - 1] + 1; // 更新递增子序列的长度
// 更新最长递增子序列的长度及其对应的数字
if (f[a[i]] > mxn) {
mxn = f[a[i]];
mx = a[i];
}
}
cout << mxn << '\n';
// 从数组末尾回溯,找到最大递增子序列的索引
for (int i = n; i >= 1; i--) {
if (a[i] == mx) {
ans.push_back(i); // 找到的索引加入结果
mx--; // 下一个目标数字
}
}
for (int i = ans.size() - 1; i >= 0; i--) {
cout << ans[i] << " ";
}
return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现