Codeforces Round 1006 (Div. 3) 比赛记录
Codeforces Round 1006 (Div. 3) 比赛记录
比赛链接
这场的题目名称都很长啊~。
很简单的一场(毕竟是div3,能不简单嘛)赛时切掉了A - F,C题花的时间有点多,G题偶遇数学压轴拼尽全力无法战胜。
A. New World, New Me, New Array
由于取值范围是
void solve()
{
int n, k, p;cin >> n >> k >> p;
k = abs(k);
int mx = n * p;
if(k == 0) {
cout << 0 << '\n';
return;
}
if(k > mx) {
cout << -1 << '\n';
return;
} else {
cout << (k - 1) / p + 1 << '\n';
}
}
B. Having Been a Treasurer in the Past, I Help Goblins Deceive
组合数学问题,两个 - 和一个 _ 来组成一个表情,很明显,要最多的话,我们把所有的 _ 放在一起是最有的,因为此时他们可以共享所有的 -,然后再枚举一下左右两边 - 的数量乘一下取最大即可。
void solve()
{
int n;cin >> n;
string s;cin >> s;
int cnt = 0;
int ck = 0;
for(auto &i : s) {
cnt += (i == '-');
ck += (i == '_');
}
int ans = 0;
for(int i = 1;i <= cnt;i ++) {
ans = max(ans, i * (cnt - i) * ck);
}
cout << ans << '\n';
}
C. Creating Keys for StORages Has Become My Main Skill
题目要我们构造出来的
赛后在群里看到了其他大佬更优雅的做法:先把
//其实这个check可以直接用 x | i == i来替换,赛时铸币了
bool check(int x, int y) {
for(int i = 0;i <= 31;i ++) {
if(!(x & (1ll << i)) && (y & (1ll << i))) {
return false;
}
}
return true;
}
void solve()
{
int n, x;cin >> n >> x;
int ix = 0;
for(int i = 0;ix < n;i ++) {
if(check(x, i)) {
a[++ ix] = i;
} else break;
}
int pre = 0;
for(int i = 1;i <= ix;i ++) {
pre |= a[i];
}
if(pre != x) {
if(ix == n)a[ix] = x;
else a[++ ix] = x;
}
while(ix <= n) {
a[++ ix] = 0;
}
for(int i = 1;i <= n;i ++) {
cout << a[i] << " \n"[i == n];
}
}
D. For Wizards, the Exam Is Easy, but I Couldn't Handle It
选择一个子区间,把区间头移动到尾部,使得改动后逆序对尽可能少。
看到逆序对,首先想到了树状数组,然后一看数据范围:
直接
枚举每一个点
void solve()
{
int n;cin >> n;
for(int i = 1;i <= n;i ++)cin >> a[i];
pair<int, int> ans = {1, 1};
int mx = 0;
int sum[2] = {0};
for(int i = 1;i <= n;i ++) {
sum[1] = 0;
sum[0] = 0;
for(int j = i + 1;j <= n;j ++) {
if(a[j] < a[i])sum[1] ++;
if(a[j] > a[i])sum[0] ++;
int now = sum[1] - sum[0];
if(now > mx) {
ans = {i, j};
mx = now;
}
}
}
cout << ans.first << ' ' << ans.second << '\n';
}
E. Do You Love Your Hero and His Two-Hit Multi-Target Attacks?
这个题可以用类似倍增的想法来做。
如果一堆点
那么我们可以先预处理
为了节约,我们可以一条竖着一条横着这么放,这样每次都可以省下来一个(但其实是不需要的,只需要每次结束时
void init() {
for(int i = 1;i <= 500;i ++) {
a[i] = i * (i - 1) / 2;
}
}
void solve()
{
int k;cin >> k;
int ix = upper_bound(a + 1, a + 500 + 1, k) - a;
int sum = k;
int cnt = 0;
int x = 0;
int y = 0;
vector<pair<int, int> > ans;
ans.push_back({0, 0});
while(sum) {
cnt ++;
int ix = upper_bound(a + 1, a + 500 + 1, sum) - a - 1;
sum -= a[ix];
if(cnt & 1) {
x ++;
for(int i = 1;i < ix;i ++) {
ans.push_back({x, y});
x ++;
}
x --;
} else {
y ++;
for(int i = 1;i < ix;i ++) {
ans.push_back({x, y});
y ++;
}
y --;
}
}
cout << ans.size() << '\n';
for(auto &[u, v ] : ans) {
cout << u << ' ' << v << '\n';
}
}
F. Goodbye, Banker Life
手玩几个样例后发现和
打表可以发现,如果
因此选择递归实现:
- 如果
是偶数,那就往 递归,传递时把每个值相邻堆叠两次。 - 如果
是奇数,那么 就是偶数,向 递归,然后按题目规则算 行即可。
但实际上这个做法是复杂了的,因为其实每一个位置异或上
所以只需要计算这个位置的组合数是奇数还是偶数,就知道这个位置是
最后全部乘上
(不过我觉得递归做法也还是蛮巧妙的)
void get(int x) {
if(x == 1) {
a[1] = 1;
return;
}
if(x & 1) {
get(x - 1);
for(int i = 1;i <= x;i ++) {
if(i == 1) {
tmp[i] = a[i];
} else if(i == x) {
tmp[i] = a[1];
} else {
tmp[i] = a[i - 1] ^ a[i];
}
}
for(int i = 1;i <= x;i ++) {
a[i] = tmp[i];
}
} else {
get(x / 2);
for(int i = 1;i <= x / 2;i ++) {
tmp[i * 2] = tmp[i * 2 - 1] = a[i];
}
for(int i = 1;i <= x;i ++) {
a[i] = tmp[i];
}
}
}
void solve()
{
int n, k;cin >> n >> k;
get(n);
for(int i = 1;i <= n;i ++) {
cout << a[i] * k << " \n"[i == n];
}
}
离 AK 最近的一次,希望有朝一日能 AK div3!
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?
· Pantheons:用 TypeScript 打造主流大模型对话的一站式集成库