24暑期第三次训练C组题解
A 津津的储蓄计划
模拟题, 按题意模拟即可.
void func()
{
int jin = 0,mom = 0;
// jin为津津手上的钱, mom为妈妈手上存的钱.
vector<int> pay(12);// 开一个vector数组, 存12个月的开支(也可以在线计算)
for(auto &i : pay) cin >> i;// auto遍历, 后面会详细讲.
for(int i=0;i<12;++i)
{
jin += 300;
jin -= pay[i];
if(jin < 0)
{
cout << -(i+1) << '\n';//下标从0开始,答案需+1
return;
}
mom += (jin / 100)*100;// 津津手上整百的钱, 交给妈妈保管.
jin %= 100;
}
int ans = jin + mom*1.2;// 答案直接输出会cout浮点型, 在cout加强制类型转换也可.
cout << ans << '\n';
}
auto遍历:
- auto
自动识别类型
视频讲解auto n = 10; // n被赋值整型数据, auto自动将n声明为整型变量.
- auto遍历
视频讲解for(类型 变量 : 容器名) // 可以遍历一个容器(从头到尾) string s1; for(chat i : s1) cout << i; //此时可遍历s1, 将s1输出. // 因为auto可以自动推断类型, 所以这类遍历方法可以都用auto代替 vector<int> a(12); for(auto &i : a) cin >> i; // 变量前放'&'时, 可对元素读写, 不加则只能读.
B 校门外的树
模拟题, 因为数据较小可以直接开数组存树, 也可以用区间合并.
void func()
{
int l,m,ans = 0;
cin >> l >> m;
int u,v;
bool tree[N];
memset(tree,1,sizeof tree);//初始化,种树. 后续会有memset()函数用法
while(m--)
{
cin >> u >> v;
for(int i=u;i<=v;++i) tree[i] = 0;// 砍树
}
for(int i=0;i<=l;++i)
{
ans += tree[i];// 清点总数
}
cout << ans << '\n';
}
memset()
时间复杂度O(n)
给数组初始化为一个固定值, 此处就给bool数组初始化为1.
但是int数组只能初始化为-1, 0, 或者无穷大. 详情请看此篇博客
区间合并做法:
void func()
{
int l,m;
cin >> l >> m;
vector<pair<int,int>> a(m),b;
for(int i=0;i<m;++i) cin >> a[i].x >> a[i].y;
sort(a.begin(),a.end());
int u = a[0].x,v = a[0].y;
for(int i=1;i<m;++i)
{
if(a[i].x <= v)
{
if(a[i].y > v) v = a[i].y;
}
else
{
b.push_back({u,v});
u = a[i].x,v = a[i].y;
}
}
b.push_back({u,v});
int ans = l+1;
for(auto &i : b)
{
ans -= (i.y - i.x + 1);
}
cout << ans << '\n';
}
区间排序和二元组自行了解.
C 杨辉三角
因为是数组, 所以每个元素从左上一个和正上的和组成.
void func()
{
int n;
cin >> n;
int a[n][n];
memset(a,0,sizeof a);
for(int i=0;i<n;++i)
{
a[i][0] = 1;
a[i][i] = 1;
}
for(int i=2;i<n;++i)
{
for(int j=1;j<i;++j)
{
a[i][j] = a[i-1][j-1] + a[i-1][j];
}
}
for(int i=0;i<n;++i)
{
for(int j=0;j<=i;++j) cout << a[i][j] << ' ';
cout << '\n';
}
}
D Special Characters
相同字符连续情况, 在个数为1时, 不产生特殊字符. 在个数大于等于2时, 这组字符的收尾构成特殊字符. 所以可推得: 特殊字符两两出现, n为奇数时, 必不可能.
void func()
{
int n;
cin >> n;
if(n&1)// 判断n的奇偶
{
cout << "NO\n";
return;
}
else cout << "YES\n";
n /= 2;// 因为字符两辆出现, 所以可以/2, 方便后续计算.
// 可以根据n奇偶选择A/B
while(n)
{
n --;
n & 1 ? cout << "BB" : cout << "AA";// 三目运算符
// 因为只要不同字符, 所以用AB两种即可.
}
cout << "\n";
}
位运算&
算竞里会经常用到位运算, 尤其很多题目专门考察位运算.
& 与
| 或
^ 异或
! 非
原理自查.
三目运算符
条件 ? 结果1 : 结果2
条件为真时, 执行结果1. 为假执行结果2.
E Strange Splitting
可以只有一个元素, 这时其范围为0.
这样另一组只需要范围不为0即可.
给出已经是升序. 只要第一个数和最后一个数不相同则可选出范围不同的两组(a[0] == a[n-1]代表所有元素均相等).
void func()
{
int n;
cin >> n;
vector<int> a(n);
for(auto &i : a) cin >> i;
if(a[0] == a[n-1])
{
cout << "NO\n";
return ;
}
cout << "YES\n";
if(a[n-1] == a[1])// 如果第二个数和最后一个相等, 那么选择这组, 范围也为0.
{
// 选择0~n-2 和 n-1
for(int i=0;i<n-1;++i) cout << 'R';
cout << 'B';
}
else
{
// 选择0 和 1~n-2
cout << 'R';
for(int i=1;i<n;++i) cout << 'B';
}
cout << '\n';
}
F Stickogon
正多边形, 由3+条边组成. 每3条边可以组成一个正多边形(一个正六边形可以组成两个正三角形).
void func()
{
int n,ans = 0;
cin >> n;
map<int,int> cnt;// 清点每种个数
int stp;
while(n--)
{
cin >> stp;
cnt[stp]++;
}
for(auto &i : cnt)// auto遍历, 这时每个i是一个二元组.
{
ans += (i.second/3);
}
cout << ans << '\n';
}
G Card Exchange
首先, 对于每组牌, 牌数越多, 越有可能进行更多的交换.
然后, 每组牌获得相同数的牌, 这组牌越多, 越可能进行更多交换.
所以, 只需要每次对最多牌数的组操作, 将其加入第二多的组.
这时排序是动态的, 因为需要实时的最多组, 所以要用的优先队列(堆).
stl的priority_queue, 自行学习.
struct PII// 构造二元组
{
int x,y;
bool operator < (const PII &i) const// 重载预算符, 使得堆先根据二元组的第二个元素从大到小排, 再第一个元素从大到小排.
{
return (y == i.y ? x < i.x : y < i.y);
}
};
void func()
{
int n,k,ans = 0;
cin >> n >> k;
map<int,int> cnt;
int stp;
while(n--)
{
cin >> stp;
cnt[stp]++;
}
priority_queue<PII> pq;// 优先队列(堆)
// 此处也可以不重载, 用stl的二元组, 只需将牌数放第一个元素即可.
for(auto &i : cnt) pq.push({i.x,i.y});
while(pq.top().y >= k)
{
auto stp1 = pq.top();pq.pop();
stp1.y -= k;
pq.push(stp1);
auto stp2 = pq.top();pq.pop();
stp2.y += (k-1);
pq.push(stp2);
}
while(pq.size())
{
ans += pq.top().y;
pq.pop();
}
cout << ans << '\n';
}
构造结构体和重载运算符
结构体: c的语法, 不记得自学.
重载运算符: 如上是重载 < 运算符的方法, 其他自行了解.
对于< , ab两个元素, 如果a < b为真, 那么a在前, b在后.
这里的小于是重载后的小于.
重载小于号在需要排序的题很常用, 尤其易和堆配合.
H Least Product
可以分为三种情况:
- 出现了0, 这时r为0. 需要进行0次操作.
- 全是正数或者偶数个负数, 这时r>0, 将任意元素改为0即可时r最小, 等于0.需要进行一次操作.
- 奇数个负数, 这时r < 0. 需要进行0次操作.
void func()
{
int n;
cin >> n;
vector<int> a(n);
for(auto &i : a) cin >> i;
int cnt = 0;
bool sign = false;
for(auto &i : a)
{
if(i == 0) sign = true;
if(i < 0) cnt++;
}
if(cnt&1 || sign) cout << 0 << '\n';
else cout << 1 << '\n' << 1 << ' ' << 0 << '\n';
}
I 选数
难点在于怎么选k个数, 用dfs, 自行了解, 教程很多.
int n,k,ans;
int a[N];
void dfs(int,int,int);
bool slove(int);
int main(void)
{
cin >> n >> k;
for(int i=0;i<n;++i) cin >> a[i];
for(int i=0;i<n;++i) dfs(i,1,a[i]);
cout << ans << '\n';
return 0;
}
void dfs(int z,int cnt,int sum)// 传入分别是: 前一个加上第几个数, 已经加了几个数, 总和.
{
if(cnt == k) ans += slove(sum);
else
{
for(int i=z+1;i<n;++i) dfs(i,cnt+1,sum+a[i]);
}
}
bool slove(int z)// 判断是否是素数.
{
if(z == 1) return false;
for(int i=2;i<=z/i;++i)
{
if(z % i == 0) return false;
}
return true;
}
DFS
如图为DFS遍历树.
J Peter的烟
福利题, 原本在这里是道很难的数学题, 但是太蓝桥杯了被改掉了.
夹带私活 —— 《死一样的抽过》
void func()
{
int n, k;
int butt = 0,ans = 0;// 烟蒂数和抽数
cin >> n >> k;
butt += n;
ans += n;
while(butt >= k)
{
ans += (butt/k);//
butt = (butt/k + butt%k); //新换的烟的烟蒂和换掉后余下烟蒂
}
cout << ans << '\n';
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
· 25岁的心里话