CF补题 981-Div.3

CF补题 981-Div.3-20241226

Dashboard - Codeforces Round 981 (Div. 3) - Codeforces

A:

题目大意:\(x\)\(0\) 开始,轮流将 \(x\) 前后移动 \(i*2-1\), 求最后移动出 \([-n,n ]\) 的 操作数 $ i$

#include <iostream>
#include <math.h>
using namespace std;
int main()
{
int T;
cin >> T;
while (T--)
{
int n;
int x = 0;
cin >> n;
int i = 0;
for (i = 1; x >= -n && x <= n; i++)
x += (2 * i - 1) * pow(-1, i);
if (i % 2 == 1) cout << "Kosuke" << endl;
else cout << "Sakurako" << endl;
}
return 0;
}

转化方程为每次移动 \((2*i-1)*(-1)^i\) 个单位,最后对操作数 $ i$ 取余

B:

题目大意:给定一个矩阵,每次可以选取任意一条正斜线,使斜线上的数都 \(+1\) ,求矩阵所有元素都大于 \(0\) 的操作数

#include <iostream>
#include <algorithm>
#include <cstring>
using namespace std;
int a[505][505];
int dg[1010];//所有斜线上最小元素
int main()
{
int T;
cin >> T;
while (T--)
{
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= n; j++) {
cin >> a[i][j];
dg[j - i + n] = min(dg[j - i + n], a[i][j]);//贪心更新
}
}
int ans = 0;
for (int i = 1; i < 2 * n; i++) ans -= dg[i];//累加答案
cout << ans << endl;
memset(dg, 0, sizeof dg);//多测清空
}
return 0;
}

贪心策略,每次记录当前输入的元素,更新该斜线上的最小值,最后所有斜线上的数之和,即所有的最大负数和 $ \sum_i^n min(dg_i)$

即至少操作这么多次,才能满足条件

C:

题目大意:给定一个序列,每次可以交换第 \(i\) 和第 \(n-i+1\) 个位置上的数,求使得序列上的元素满足任意 \(a_j=a_{j+1}\) 的最小组合

#include <iostream>
using namespace std;
int a[200010];
int main()
{
int T;
cin>>T;
while (T--){
int n;
cin>>n;
for (int i=1;i<=n;i++) cin>>a[i];
int l=2,r=n-1;
while (r>l){
if (a[l]==a[l-1]||a[r]==a[r+1])
swap(a[l],a[r]);
l++;r--;
}
int ans=0;
for (int i=2;i<=n;i++)
if (a[i]==a[i-1]) ans++;
cout<<ans<<endl;
}
return 0;
}

双指针,贪心(?

两个指针从左右两边开始移动,如果存在 \(a_i=a_{i-1}\) 就交换,当前局部的最优解可以推出全局的最优解(?

证明有:

设序列 1 4 3 5 1 1 3 (干扰度为 \(1\)) ,定义l=1,r=n-2,此时序列中 a[l]=4,a[r]=1,不交换。两个指针向中间移动。移动后 a[l]=3,a[r]=1r与后一个元素相同,交换 lr ,序列为 1 4 1 5 3 1 3 全局干扰度减 \(1\) ,以此类推。。。

设序列 3 1 3 2 2 3 3 (干扰度为 \(2\)),定义l=1,r=n-2,此时序列中 a[l]=1,a[r]=3r和后一个元素相同,若 lr 交换,序列变为 3 3 3 2 2 1 3l 与前一个元素相同,则全局的干扰度没有变化。两个指针向中间移动,l与前一个元素相同,交换 lr3 3 2 2 3 1 3 ,全局的干扰度不变。 最终全局最优的干扰度就为 \(2\)

归纳发现,如果满足交换条件的 lr ,就一定要交换,交换后全局解一定不劣,要么为优要么不变

D:

题目描述:给出一段序列,计算不重叠区间 l,r 使得 \(\sum _{i=l}^r a_i=0\) 的最大区间个数

#include <iostream>
#include <map>
#include <set>
using namespace std;
long long a, b, ans;
set<long long> mem;
void init(void) {
mem.clear();
b = 0;
mem.insert(0);
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int T;
cin >> T;
while (T--) {
ans = 0;init();
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a;
b += a;
if (mem.count(b)) {
ans++;
init();
}
else
mem.insert(b);
}
cout << ans << endl;
}
return 0;
}

前缀和+贪心,每个区间右端点越靠左越优,如果某元素前缀和与前面已经记录的相同,答案 +\(1\)

使用集合set来记录前缀和,注意要首项要加入 \(0\) ,因为序列头为 \(0\) 时,也可以算作答案区间

数据量较大时关同步流可以明显加速

  • 不开long long见祖宗
posted @   才瓯  阅读(6)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示