2021杭电多校补题(6)

1001题目链接

题意:给定数x,求包含x的区间和为素数的最小区间长度
分析:
显然 r > 0,r ≥ l,如果 l ≤ 0,此时 [l,r] 区间和 = [−l + 1,r] 的区间和,且 r ≥ −l + 1 > 0。
故对于任意一个区间,都可以找到一个对应的 r ≥ l > 0 的区间与之对应,区间和相同。对于下式: ∑ i = l r i = ( l + r ) ( r − l + 1 ) 2 \sum_{i=l}^ri=\frac{(l+r)(r-l+1)}{2} i=lri=2(l+r)(rl+1)

当 l > 0 时,若 r − l ≥ 2,则 l + r 2 \frac{l+r}{2} 2l+r r − l + 1 2 \frac{r-l+1}{2} 2rl+1之中必有一个是大于 1 的整数。区间和必然能被拆分成两个因数的乘积。所以这样的满足和为素数的区间长度必然不长于 2。

预处理出比 [2,2 × 10 7 ] 略大范围内的质数,埃氏筛或者线筛均可。

如果 x ≤ 0,则候选答案为:

  • 最小的 y(y ≥ 1 − x),满足 y 是质数,区间为 [−y + 1,y]。
  • 最小的 z(z ≥ 2 − x),满足 2z − 1 是质数,区间为 [−z + 2,z]。

如果 x > 0,则候选答案为:

  • [x,x]。
  • [x,x + 1]。
  • [x − 1,x]。
  • 最小的 y(y ≥ x),满足 y 是质数,区间为 [−y + 1,y]。
  • 最小的 z(z ≥ x),满足 2z − 1 是质数,区间为 [−z + 2,z]。
    二分查找即可,时间复杂度为 O(T log(|x|) + |x|)。
#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
#include<string>
#include<queue>
#define maxn 20000010
using namespace std;
int prime[maxn];
int visit[maxn];
void Prime() {
    memset(visit, 0,sizeof(visit));
    memset(prime, 0,sizeof(prime));
    visit[0] = 1;
    visit[1] = 1;
    for (int i = 2; i <= maxn; i++) {
        if (!visit[i]) {
            prime[++prime[0]] = i;
        }
        for (int j = 1; j <= prime[0] && i * prime[j] <= maxn; j++) {
            visit[i * prime[j]] = 1;
            if (i % prime[j] == 0) {
                break;
            }
        }
    }
}
int main()
{
	int t;
    Prime();
	scanf("%d", &t);
	while (t--)
	{
		int x;
		scanf("%d", &x);
        int minindex = maxn;
		if (x <= 0)
		{
            int i;
            for (i = 1 - x; visit[i]; ++i);
            minindex = min(minindex, 2 * i);
            for (i = 2 - x; visit[2 * i - 1]; ++i);
            minindex = min(minindex, 2*i-1);
            printf("%d\n", minindex);
		}
        else
        {
            int i = 0;
            if (!visit[x])
                printf("1\n");
            else
            {
                if (!visit[2 * x + 1] || !visit[2 * x - 1])
                    printf("2\n");
                else
                {
                    for (i = x; visit[i]; ++i);
                    minindex = min(minindex, 2*i);
                    for (i = x; visit[2 * i - 1]; ++i);
                    minindex = min(minindex, 2 * i - 1);
                    printf("%d\n", minindex);
                }
            }
        }
	}
	return 0;
}

1005 题目链接

题目大意:

给定整数 1 , 2 , ⋯ , n 把这些数字分成m个不相交的集合,使第j个集合的中位数为bj。确定这是否可能。
注:这题中,偶数个数的集合的中位数取中间两个数中较小的那个。

题目分析:

题目分析:
显然 b 1 b_1 b1, b 2 b_2 b2,··· , b m b_m bm 这 m 个数要放在 m 个不同的集合中,剩下的 n − m 个数字要放到这 m 个集合里且不影响每个集合的中位数。
使用一个例子以方便说明:假设 n = 6,m = 2, b 1 b_1 b1 = 3, b 2 b_2 b2 = 5,那么 1,2,··· ,n 这些数会被b分成 1,2、4、6 这三段,且任意两段中的任意一对数字可以配对消掉。
所以最后剩下的所有数字一定是同一段内的。
因此讨论两种情况:

  • 如果长度最大的段的数字个数不大于其它段的数字个数之和,那么最终要么全部消掉,要么剩下一个,且剩下的这个数可以在任何一段内。
    如果会剩下,不妨将最后一段的数字剩下一个,此时再把最后一段的数字放到中位数最小的集合中即可满足题意,所以答案为 YES。
  • 如果长度最大的段的数字个数大于其它段的数字个数之和,那么最终剩下的所有数字都在最大的这段内。
    设中位数小于这一段的最小值的集合的个数为 x,容易发现当且仅当 x 不小于这一段剩下的数字个数时有解。
    时间复杂度 O ( n ) O(n) O(n)
AC代码:
#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<iostream>
#include<vector>
#include<string>
#include<queue>
#include<algorithm>
#include<assert.h>
using namespace std;
typedef pair<int, int> Pair;
#define maxn 100005
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	int t;
	cin >> t;
	while (t--)
	{
		vector<Pair> size;
		int n, m, b[maxn];
		int flag[maxn] = { 0 };
		cin >> n >> m;
		for (int i = 1; i <=m; ++i)
			cin >> b[i],flag[b[i]] = 1;
        flag[n + 1] = 1;
		int len = 0, num = 0;
		for (int i = 1; i <=n+1; ++i)
		{
			if (flag[i])
			{
				if (len)
					size.push_back(Pair(len, num));
				len = 0;
				num++;
			}
			else
				len++;
		}
        int sum = 0;
        for (auto s : size)
            sum += s.first;
		if (size.empty())
			cout << "YES" << endl;
		else
		{
			sort(size.begin(), size.end());
			if (size.back().first <=sum - size.back().first+size.back().second)
				cout << "YES" << endl;
			else
				cout << "NO" << endl;
		}
	}
	return 0;
}

1008题目链接

分析

考虑范围为 k 的狙击手,可以攻击的范围是一个正方体。那我们不妨重新陈述一下题面,称狙击手从 ( x , y , z ) (x,y,z) (x,y,z) 可以攻击的范围是所有满足 x ≤ x ′ ≤ x + 2 k x≤x′≤ x + 2k xxx+2k, y ≤ y ′ ≤ y + 2 k y ≤ y ′ ≤ y + 2k yyy+2k, z ≤ z ′ ≤ z + 2 k z ≤ z ′ ≤ z + 2k zzz+2k ( x ′ , y ′ , z ′ ) (x ′ ,y ′ ,z ′ ) (x,y,z)

那么我们就会发现:如果我们的狙击手的某一维度的坐标小于剩余点的那一维度的最小坐标,我们就应该把狙击手移动的那一维度的最小坐标,因为这样只会让我们能狙击的目标增
多。

在我们三个维度都是那一维度的最小坐标时,狙击手就必须将三个维度中某一维度最小坐标的所有敌军都消灭,才能继续移动。这时我们可以贪心的选取所需 k 最小的敌军消灭。
复杂度 O ( n l o g n ) O(nlogn) O(nlogn)

AC代码
#define _CRT_SECURE_NO_WARNINGS
#include<cstdio>
#include<iostream>
#include<vector>
#include<cstring>
#include<assert.h>
#include<string>
#include<queue>
#include<algorithm>
#include<set>
using namespace std;
typedef pair<int, int> P;
#define maxn 500005
typedef long long ll;
int main()
{
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout.tie(0);
	int t;
	cin >> t;
	while (t--)
	{
		int n;
		cin >> n;
		set<P>sets[3];
		vector<vector<int> >pos(3,vector<int>(n+1,0));
		for (int i = 0; i < n; ++i)
		{
			cin >> pos[0][i] >> pos[1][i] >> pos[2][i];
			sets[0].insert(make_pair(pos[0][i], i));
			sets[1].insert(make_pair(pos[1][i], i));
			sets[2].insert(make_pair(pos[2][i], i));
		}
		int ans = 0;
		while (sets[0].size())
		{
			P x = *sets[0].begin(), y = *sets[1].begin(), z = *sets[2].begin();
			vector<P>k;
			for (int i = 0; i < 3; ++i)
			{
				P cur =*sets[i].begin();
				k.push_back(make_pair(max(pos[0][cur.second] - x.first, max(pos[1][cur.second] - y.first, pos[2][cur.second] - z.first)), cur.second));
			}
			sort(k.begin(), k.end());
			ans = max(ans, k[0].first);
			for (int i = 0; i < 3; ++i)
				sets[i].erase(P(pos[i][k[0].second], k[0].second));
		}
		cout << ( ans + 1 ) / 2 << endl;
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
该资源内项目源码是个人的课程设计、毕业设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。 该资源内项目源码是个人的课程设计,代码都测试ok,都是运行成功后才上传资源,答辩评审平均分达到96分,放心下载使用! ## 项目备注 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用! 2、本项目适合计算机相关专业(如计科、人工智能、通信工程、自动化、电子信息等)的在校学生、老师或者企业员工下载学习,也适合小白学习进阶,当然也可作为毕设项目、课程设计、作业、项目初期立项演示等。 3、如果基础还行,也可在此代码基础上进行修改,以实现其他功能,也可用于毕设、课设、作业等。 下载后请首先打开README.md文件(如有),仅供学习参考, 切勿用于商业用途。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值