23.9.26 CF div3总结

文章讲述了在算法竞赛中遇到的三道编程题目,涉及寻找数组中特定整数出现频率最高的子段,构造满足特定条件的递增数列,以及计算整数和的范围问题。解题过程中强调了数学方法的应用和对基础概念的理解。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

这场比赛真的受益匪浅喔。

感受到了自己写题目时候的解法真的很暴力,以致于昨天的第三题tle了。

就是说,以后写题能尽量贴近数学,能用数学方法直接求出来的值就不要用什么循环来解了。

贴题。

A:

如果一个整数在该子段上出现的次数大于该子段中任何其他整数的出现次数,则我们将其定义为该子段上最常见的整数。数组的子段是数组 a 中元素的连续段。

给定大小为 n 的数组 a 和整数 k,确定是否存在 a 的非空子段,其中 k 是最常见的元素。

输入:

每个测试由多个测试用例组成。第一行包含一个整数 t(1≤t≤1000) - 测试用例的数量。测试用例的描述如下。

每个测试用例的第一行包含两个整数 n 和 k (1≤n≤100, 1≤k≤100) - 数组中元素的数量以及必须是最常见的元素。

每个测试用例的第二行包含 n 个整数 a1、a2、a3、……、an (1≤ai≤100) - 数组的元素。

输出:

对于每个测试用例,如果存在其中 k 是最常见元素的子段,则输出“YES”,否则输出“NO”。

您可以在任何情况下输出答案(例如,字符串“yEs”、“yes”、“Yes”和“YES”将被识别为肯定答案)。

这题不知道是我理解问题还是什么,感觉很简单,只需判断k是否在数组a中即可

AC代码:

#include <bits/stdc++.h>
using namespace std;

int arr[105];

void init()
{
	
}

void solve()
{
	int n, k; cin >> n >> k;
	int flag = 0;
	for(int i = 0; i < n; ++i)
	{
		cin >> arr[i];
		if(arr[i] == k)flag = 1;
	}
	if(flag)cout << "YES" << '\n';
	else cout  << "NO" << '\n';
}

int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    
    int t = 1;cin >> t;
    init();
    while (t --)
	{
        solve();
    }
    
    return 0;
}

B

塞尔维亚信息学奥林匹克赛后,Aleksa 非常难过,因为他没有获得奖牌(他不会堆栈),所以 Vasilije 来给他出一道简单的题,只是为了让他的日子过得更好。

Vasilije 给了 Aleksa 一个正整数 n (n≥3),并要求他构造一个大小为 n 的严格递增的正整数数组,使得

  • 对于每个 i (1≤i≤n−2),3⋅a(i+2) 不能被 ai+a(i+1)整除。

请注意,大小为 n 的严格递增数组 a是一个数组,其中每个 i (1≤i≤n−1) 为 ai<ai+1

由于Aleksa现在认为自己是一个糟糕的程序员,所以他要求你帮他找到这样一个数组。

输入

每个测试由多个测试用例组成。第一行包含一个整数 t (1≤t≤1e4) - 测试用例的数量。测试用例的描述如下。

每个测试用例的第一行包含一个整数 n (3≤n≤2⋅1e5) - 数组中的元素数量。

保证所有测试用例的 n之和不超过 2⋅1e5。

输出:

对于每个测试用例,输出 n 个整数 a1,a2,a3,…,an (1≤ai≤1e9)。

可以证明任意n都有解存在。如果有多个解,输出任意一个。

这道题我想了好久,没想明白到底怎样的数列才能符合这种条件,试过a(i+2) = a(i+1) + ai - 1

但是wa了,后面仔细一想也发现不对劲,之后学长告诉了我他的思路,我大受震撼。

只需输出奇数数列就好了。

奇数加奇数是偶数,3乘奇数还是奇数,奇数如何被偶数整除。

只能说,很巧妙。

AC代码:

#include<bits/stdc++.h>
using namespace std;

void init()
{
	
}

void solve()
{
	int n; cin >> n;
	for(int i = 1; i < 2*n; i += 2)cout << i << ' ';
	cout << '\n';
}

int main()
{
	ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	
	int t = 1; cin >> t;
	init();
	while(t--)
	{
		solve();
	}

	return 0;
}

C

阿卡和米洛万是两位竞争性程序员,决定给瓦西里耶出一个问题来测试他的技能。

Vasilije 被给予三个正整数:n、k 和 x,他必须确定是否可以在 1 和 n 之间选择 k 个不同的整数,使得它们的总和等于x。

由于瓦西里耶现在身处阿卡和米洛万居住的塞尔维亚最奇怪的城市查卡克,所以这个问题对他来说似乎很奇怪。所以他需要你的帮助来解决这个问题。

输入

第一行包含一个整数 t (1≤t≤1e4) - 测试用例的数量。

每个测试用例的唯一行包含三个整数 n、k 和 x(1≤n≤2⋅1e5、1≤k≤n、1≤x≤4⋅1e10)——他可以选择的最大元素、他可以选择的元素数量以及他必须达到的总和。

请注意,所有测试用例的 n总和可能超过 2⋅1e5

输出

对于每个测试用例,输出一行:“YES”(如果可以在 1 和 n 之间选择 k 个不同的整数,使得它们的总和等于 x);“NO”(如果可以)不是。

您可以在任何情况下输出答案(例如,字符串“yEs”、“yes”、“Yes”和“YES”将被识别为肯定答案)。

这道题我第一反应就是对于每个n、k组合都会有一个对应的和的区间,但是不会证明(高考完脑子就萎缩了),在草稿纸上演算了一遍之后发现并不是(其实是我写错了),导致也卡了有一会,直到后面学长给我证明了一遍。

可以取到的最小值:前k个数的和,最大值:后k个数的和

然后,我用循环求了这个和,提交上去之后就tle了。

最后经过提醒才想起来了那个等差数列的求和公式。。。

血的教训。

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define ll long long

void init()
{
	
}

void solve()
{
	ll n, k, x; cin >> n >> k >> x;
	ll min = (1+k)*k/2, max = (n-k+1 + n)*k/2;
	if(min <= x && max >= x)cout << "YES" << '\n';
	else cout << "NO" << '\n';
}

int main() {
    ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);
    
    int t = 1;cin >> t;
    init();
    while (t --)
	{
        solve();
    }
    
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值