好久没写题了,就 A 了两题 。。
第一题
题意描述
有 组测试用例,每次测试用例给你一个 ,让你求一个数 ,使得最大公因数 为素数
数据范围
大概是 ,
解法
线性筛 + 枚举
时间复杂度
首先用线性筛求出所有的素数,然后枚举所有素数,看是否是 的约数
代码如下
#include <iostream>#include <cstring>
using namespace std;
const int N = 100010;
int p[N], cnt = 0;bool st[N];
void init(int n) {
for (int i = 2; i <= n; i ++ ) { if (!st[i]) p[cnt ++ ] = i; for (int j = 0; i <= n / p[j]; j ++ ) { st[i * p[j]] = true; if (i % p[j] == 0) break; } }}
void solve() { int n; scanf("%d", &n); // cout << cnt << endl; for (int i = 0; p[i] <= n; i ++ ) if (n % p[i] == 0) { printf("%d\n", p[i]); break; }}
int main() {
// freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout);
init(N - 1); int T; scanf("%d", &T); while (T -- ) { solve(); }}TIPhh,事实上线性筛本质上就是用一个合数的最小素数因数将该合数筛掉,因此只需要保存每个数的最小素数因子即可。所以最后的枚举多此一举,时间复杂度应该为
第二题
题意描述
给你一个长度为 的数组,然后你可以执行无限次以下操作
选择数组下标不同的两个数 ,使得数组中 ,
求使得使得这个数组极差最小的最少操作数
NOTE极差:数组中最大值和最小值之差
数据范围
解法
思维
时间复杂度
可以想象这个数组极差最小是多少?一定是 或者
假设此时极差不为 或者 ,也就是最大值 和最小值 之差 ,那么此时可以通过一次操作将这两个数的差降到 或者 。如果进行了此次调整,极差仍然不为 或者 ,继续执行改步骤即可
另外,假设 ,由于每次操作都有一个数减一,一个数加一,因此每次操作 不变。
因此,如果 ,说明最后极差一定为 ,且每个数都为 ;如果 ,说明最后极差一定为 ,且有 个数为 , 个数为
根据贪心性质,将数组从大到小排序,前面 个数变成 和后面的 个数变成 需要操作数为
最终答案就是
代码如下
#include <iostream>#include <cstring>#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010;
int q[N];int n;
int main() {
// freopen("in.txt", "r", stdin); // freopen("out.txt", "w", stdout);
scanf("%d", &n); LL sum = 0; for (int i = 0; i < n; i ++ ) scanf("%d", &q[i]), sum += q[i]; sort(q, q + n); reverse(q, q + n); LL t1 = sum / n, t2 = sum % n;
LL res = 0; for (int i = 0; i < n; i ++ ) if (i < t2) res += abs(q[i] - t1 - 1); else res += abs(q[i] - t1); printf("%lld\n", res / 2);
}CAUTION注意开 long long
WARNING下题暂未给出代码,仅给出目前思路,等 A 了之后再上传
第三题
题目大意
给你一个长度为 的数组,其数组之和为,然后接下来有两个人顺序执行两个操作
- 小红先选择一段区间 ,对该区间的每个数都乘 ,小红希望选择的区间能够让最后的 尽可能大
- 小明再选择一段区间 ,对该区间的每个数都乘 ,小明希望选择的区间能够让最后的 尽可能小
问:在经过这两个操作之后, 的值为多少?
数据范围
解法
问题一 假设最开始的数组累和为 ,修改的区间是 ,将其每个值都乘 ,最后的 是多少?
答:
问题二 值难道不是取最大值或者最小值吗?
答:这里显然不是, 是在题目限定下一个确切的值。
假设小红已经做出选择,根据问题一,小明只需要找一个最大或者最小的连续字段和便可。因此,小红要想最后的 取最大值,是所有区间里面,最后的 最大的区间
暴力
时间复杂度
根据上述分析,有一个很暴力的解法就是枚举小红选择的区间,然后小明对每个修改后的数组求一遍最大或者最小子段和,然后所有区间能求得的最大值就是
线段树优化
---Update: 2024-08-28
IMPORTANThh,这题事实上线段树就解决了,下面的分析完全不需要。 暴力枚举小红的区间,然后每个区间乘 ,线段树可以 更新;然后求最大/小连续子区间也可以线段树求。
数据结构太弱了 ~
时间复杂度
首先先把特殊情况去掉,如果 ,则无论怎么样, 的值都不会变,因此情况分为 和 ;以下分析只考虑 的情况, 的分析类似。
上面这个暴力的时间复杂度问题在于枚举了小红选择的所有区间,并且小红和小明最后所选的区间也没有任何联系,那么能否优化这部分?
答案是肯定的。我们仔细想一想,小红和小明选择的区间是否存在交叉的情况
TIP区间A: [1,5],区间B:[2,6]。区间 A B 表示交叉,如果 A 完全包含 B 或者 B 完全包含 A,不表示交叉;同时,A 和 B 没有交集也表示不交叉。
假设最后选择中,小红和小明选择的区间是由交叉部分的,如果交叉部分的和的值是等于 0 的,无论是小红还是小明,加上这个区间都没有意义,相当于两人的选择是没有交集的;如果交叉部分的和的值是大于 0 的,那么对于小明来说,不选择这个区间比选择这个区间更优,因此可以去掉这个区间;如果交叉部分的和的值是小于 0 的,那么对于小红来说,这部分区间反而给小明利用了,因此不选择这部分区间比选择这部分区间更优
综上,小红小明最终选择的两区间,一定是不交叉的。(注意可以是包含关系)
因此这里分为三种情况考虑:
假设同样枚举小红区间为
-
小红与小明区间没有交集
小明则无非是选择 或者 的最小子段和
-
小明区间完全包含小红区间
小明无非就是选择以 中以 为终点的最小子段和的区间以及 中以 r + 1 为起点的最小子段和的区间以及
-
小红区间完全包含小明区间
区间的最小字段和
可以看到上述 1、2 好求,但是 3 目前只能想到用线段树来维护,因此每次求这个区间最小字段和的时间复杂度为
写在最后,第三题有更好的解法欢迎讨论
吐槽
我太菜了,果然只有对算法融会贯通才能写出第三题嘛 ┭┮﹏┭┮