Codeforces Round 895 (Div. 3) 考试总结
前言#
首先就是不太会打 CF,主要体现在晚上熬夜太难受,不过这场的状态还是挺好的。
然后就是时间把握不好,CCF 和模拟赛基本都是
赛时实况:
A | B | C | D | E | F | G |
---|---|---|---|---|---|---|
√ | √ | √ | √ | × | × | × |
赛后改题情况:
A | B | C | D | E | F | G |
---|---|---|---|---|---|---|
√ | √ | √ | √ | √ | √ | √ |
只看了 F 题的 tj,其他的都是自己改的。
A. Two Vessels#
Problem#
有分别装有
Solve#
水题。
总水量保持不变,所以两个杯子在操作完之后的单位水量为
Code#
#include <bits/stdc++.h>
#define ll long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
using namespace std;
namespace Read {
template <typename T>
inline void read(T &x) {
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x*=f;
}
template <typename T, typename... Args>
inline void read(T &t, Args&... args) {
read(t), read(args...);
}
}
using namespace Read;
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
int T, a, b, c;
void solve() {
read(a, b, c);
cout << ceil(abs(1.0 * (a + b) / 2 - a) / c) << '\n';
}
signed main() {
read(T);
while(T--) {
solve();
}
return 0;
}
B. The Corridor or There and Back Again#
Problem#
有无限个房间,并且向右延伸。你现在需要从
求最远能到达的
Solve#
此题花费了我一点点的时间。
首先必须有去有回。当一个陷阱被出发后,你必须在某个点折返回来,并且要保证不能受陷阱影响。对于所有的陷阱,都是如此。每个陷阱都会有一个最大的,能到达并且能返回的点,将其记为
考虑如何计算
Code#
#include <bits/stdc++.h>
#define ll long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
#define inf 1e9
using namespace std;
namespace Read {
template <typename T>
inline void read(T &x) {
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x*=f;
}
template <typename T, typename... Args>
inline void read(T &t, Args&... args) {
read(t), read(args...);
}
}
using namespace Read;
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
int T, n, d, s, k;
void solve() {
read(n);
k = inf;
For(i,1,n) {
read(d, s);
k = min(k, d + (s - 1) / 2);
}
cout << k << '\n';
}
signed main() {
read(T);
while(T--) {
solve();
}
return 0;
}
C. Non-coprime Split#
Problem#
给定
若有多组解,任意输出一组。
Solve#
构造题。
要意识到一点,就是
- 若
为偶数, ; - 若
为奇数, , ;
若
因为
时间复杂度
Code#
#include <bits/stdc++.h>
#define ll long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
#define inf 1e9
using namespace std;
namespace Read {
template <typename T>
inline void read(T &x) {
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x*=f;
}
template <typename T, typename... Args>
inline void read(T &t, Args&... args) {
read(t), read(args...);
}
}
using namespace Read;
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
const int N = 1e7 + 10;
int T, l, r, p[N], len, prime[N], tot, st[N];
vector<int> v[N];
void init() {
for (int i = 2; i <= 1e7; i++) {
if(!st[i]) prime[++tot] = i;
for (int j = 1; j <= tot; j++) {
if(i * prime[j] > 1e7) break;
st[i * prime[j]] = 1;
if(i % prime[j] == 0) break;
}
}
}
void solve() {
read(l, r);
if(r & 1) r--;
if(r < l) {
r++;
len = 0;
if(!st[r]) {
puts("-1");
return ;
}
For(i,2,sqrt(r)) {
if(st[i]) continue;
if(r % i == 0) {
cout << i << ' ' << r - i << '\n';
return ;
}
}
return ;
}
if(r / 2 == 1) {
puts("-1"); return ;
}
cout << r / 2 << ' ' << r / 2 << '\n';
}
signed main() {
read(T);
init();
while(T--) {
solve();
}
return 0;
}
D. Plus Minus Permutation#
Problem#
给定三个整数
求所有长度为
Solve#
不是一眼能懂得题了。
分析一下:要想分数最大,
细节问题就是:那些
最后答案为:
看着有点吓人,其实写起来也有亿点点吓人
Code#
#include <bits/stdc++.h>
#define int long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
#define inf 1e9
using namespace std;
namespace Read {
template <typename T>
inline void read(T &x) {
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x*=f;
}
template <typename T, typename... Args>
inline void read(T &t, Args&... args) {
read(t), read(args...);
}
}
using namespace Read;
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
const int N = 1e7 + 10;
int T, n, x, y;
void solve() {
read(n, x, y);
int l1 = n / x, l2 = n / y, l3 = n / (x * y / __gcd(x, y));
l1 -= l3, l2 -= l3;
cout << ((2 * n - l1 + 1) * l1 / 2) - ((1 + l2) * l2 / 2) << '\n';
}
signed main() {
read(T);
while(T--) {
solve();
}
return 0;
}
E. Data Structures Fan#
Problem#
给定一个长度为
1 l r
,表示将 的所有 取反( 变 , 变 );2 g
,表示将所有 的 求异或和;
.
Solve#
脑瘫题,不知道为啥这道题要放在 E。
首先,我们可以计算出操作二中一个串为
对于操作一,无非是将
维护一个前缀异或和即可。但是我打的是线段树(因为一时脑抽没有想到前缀和
时间复杂度
Code#
#include <bits/stdc++.h>
#define ll long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
#define ls p<<1
#define rs p<<1|1
using namespace std;
namespace Read {
template <typename T>
inline void read(T &x) {
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x*=f;
}
template <typename T, typename... Args>
inline void read(T &t, Args&... args) {
read(t), read(args...);
}
}
using namespace Read;
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
const int N = 1e5 + 10;
struct Node {
int l, r, val;
} t[N << 2];
int n, T, q, a[N], p0, p1;
string s;
void pushup(int p) {
t[p].val = t[ls].val ^ t[rs].val;
}
void build(int p, int l, int r) {
t[p].l = l, t[p].r = r;
if(l == r) {
t[p].val = a[l];
return ;
}
int mid = (l + r) >> 1;
build(ls, l, mid);
build(rs, mid + 1, r);
pushup(p);
}
int ask(int p, int l, int r) {
if(l <= t[p].l && t[p].r <= r) {
return t[p].val;
}
int mid = (t[p].l + t[p].r) >> 1, ans = 0;
if(l <= mid) ans ^= ask(ls, l, r);
if(r > mid) ans ^= ask(rs, l, r);
return ans;
}
void solve() {
p0 = p1 = 0;
read(n);
For(i,1,n) read(a[i]);
cin >> s;
s = " " + s;
For(i,1,n) {
if(s[i] == '0') p0 ^= a[i];
else p1 ^= a[i];
}
build(1, 1, n);
read(q);
while(q--) {
int op; read(op);
if(op == 1) {
int l, r, p;
read(l, r);
p = ask(1, l, r);
p0 ^= p, p1 ^= p;
} else {
int g; read(g);
if(g == 0) cout << p0 << ' ';
else cout << p1 << ' ';
}
}
cout << '\n';
}
signed main() {
read(T);
while(T--) {
solve();
}
return 0;
}
F. Selling a Menagerie#
Problem#
动物园里有
考虑卖掉这些动物时:
- 若
在 还没有卖掉之前就被卖掉了,现在卖掉 ,可以获得 元; - 若
在 还没有卖掉之前没被卖掉,现在卖掉 ,可以获得 元;
求最多能赚多少钱。
Solve#
首先,对于动物
反过来想:如果一个动物没有任何其他的动物怕它,那么现在卖掉这个动物之后所得到的贡献肯定不劣。因为它的存在不会影响到其他动物卖出所得的贡献。
如果把“害怕”看成一种连边关系,那么问题就很好解决了。
连边之后,会出现没有构成环的点,和构成环的点。没有构成环的点的卖出顺序随意,上文已经解释过了(没有构成环的点的存在不会影响到其他动物卖出所得的贡献)。不过要注意的是,每一条链上的点或导出子树上的点要按顺序选,不过其都会被选中。
而构成环的点的卖出顺序至关重要,换句话说,起点和终点的所在位置非常关键。起点肯定是要选择
由于每一个点只会被遍历一次,时间复杂度
Code#
#include <bits/stdc++.h>
#define int long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
#define inf 1e10
using namespace std;
namespace Read {
template <typename T>
inline void read(T &x) {
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x*=f;
}
template <typename T, typename... Args>
inline void read(T &t, Args&... args) {
read(t), read(args...);
}
}
using namespace Read;
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
const int N = 1e5 + 10;
int T, n, a[N], d[N], c[N], ans, Ans[N], len;
bool vis[N];
void solve() {
memset(vis, 0, sizeof vis);
ans = len = 0;
read(n);
For(i,1,n) read(a[i]), d[a[i]]++;
For(i,1,n) read(c[i]);
bool f = 1;
while(f) {
f = 0;
For(i,1,n) {
if(!d[i] && !vis[i]) Ans[++len] = i, d[a[i]]--, vis[i] = 1, f = 1;
}
}
For(i,1,n) {
if(d[i]) {
int x = i, mn = inf, en, st;
while(!vis[x]) {
vis[x] = 1;
if(mn > c[x]) {
mn = c[x];
st = a[x];
en = x;
}
d[a[x]]--;
x = a[x];
}
while(st != en) {
Ans[++len] = st;
st = a[st];
}
Ans[++len] = en;
}
}
For(i,1,len) cout << Ans[i] << ' ';
cout << '\n';
}
signed main() {
read(T);
For(i,1,T) {
solve();
}
return 0;
}
G. Replace With Product#
Problem#
给定一个长度为
- 选择两个正整数
,将 的所有数删除,并替换为 ;
最后的总贡献为所有数的加和,请选择 ,最大化总贡献。
Solve#
小 trick 题。
首先,前缀和后缀
发现一个性质:如果一些数的乘积很大,达到了某一个上限时,这些数的和一定比这些数的乘积要小。这个上限具体为多少我们并不知道,但是,只要它是一个很大的数字,那么上述事件发生的概率就会很大。考虑到
对于所有乘积大于上限的数,直接摒弃前缀和后缀
显然,操作区间的左右端点不会出现在数字
时间复杂度
Code#
#include <bits/stdc++.h>
#define int long long
#define H 19260817
#define rint register int
#define For(i,l,r) for(rint i=l;i<=r;++i)
#define FOR(i,r,l) for(rint i=r;i>=l;--i)
#define MOD 1000003
#define mod 1000000007
#define inf 1e18
using namespace std;
namespace Read {
template <typename T>
inline void read(T &x) {
x=0;T f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
x*=f;
}
template <typename T, typename... Args>
inline void read(T &t, Args&... args) {
read(t), read(args...);
}
}
using namespace Read;
void print(int x){
if(x<0){putchar('-');x=-x;}
if(x>9){print(x/10);putchar(x%10+'0');}
else putchar(x+'0');
return;
}
const int N = 2e5 + 10;
int T, n, a[N], sum[N], ans, ansl, ansr, len, no1[N], pre[N];
void solve() {
read(n);
For(i,1,n) read(a[i]), sum[i] = sum[i-1] + a[i];
int l, r, k; __int128 p = 1; len = 0, ans = 0, ansl = 1, ansr = 1;
For(i,1,n) {
p *= a[i];
if(p > inf) break;
}
if(p > inf) {
For(i,1,n) {
l = i;
if(a[i] != 1) {
break;
}
}
FOR(i,n,1) {
r = i;
if(a[i] != 1) {
break;
}
}
cout << l << ' ' << r << '\n';
return ;
}
pre[0] = 1;
For(i,1,n) pre[i] = pre[i-1] * a[i];
For(i,1,n) {
if(a[i] != 1) no1[++len] = i;
}
For(i,1,len) {
For(j,1,len) {
if(no1[i] > no1[j]) continue;
if(ans < sum[n] - (sum[no1[j]] - sum[no1[i]-1]) + (pre[no1[j]] / pre[no1[i]-1])) {
ans = sum[n] - (sum[no1[j]] - sum[no1[i]-1]) + (pre[no1[j]] / pre[no1[i]-1]);
ansl = no1[i], ansr = no1[j];
}
}
}
cout << ansl << ' ' << ansr << '\n';
}
signed main() {
read(T);
while(T--) {
solve();
}
return 0;
}
作者:Daniel-yao
出处:https://www.cnblogs.com/Daniel-yao/p/17689788.html
版权:本作品采用「署名-非商业性使用-相同方式共享 4.0 国际」许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· C#/.NET/.NET Core优秀项目和框架2025年2月简报
· Manus爆火,是硬核还是营销?
· 一文读懂知识蒸馏
· 终于写完轮子一部分:tcp代理 了,记录一下