2022-04-21每日刷题打卡

这篇博客探讨了如何优化算法,通过质因数分解和线性筛法解决数论问题,同时介绍了线段树的数据结构,展示了如何用线段树处理区间修改和查询最大子数组和的问题。涉及的知识点包括质因数分解、线性筛和线段树的实现与应用。
摘要由CSDN通过智能技术生成

2022-04-21每日刷题打卡

代码源——每日一题

互质 - 题目 - Daimayuan Online Judge

题目描述

给你一个包含n个正整数的序列 A=(A1,A2,…,An),找到 [1,m]中每一个满足下列条件的 k:

gcd(Ai,k)=1, 1≤i≤n

输入描述

第一行输入两个整数 n, m 第二行输入n个整数代表序列A

输出描述

第一行输出一个整数代表满足条件的k的数量 接下里每一行输出一个整数,代表一个满足条件的k

样例输入

3 12
6 1 5

样例输出

3
1
7
11

数据范围

1≤n,m≤100000 1≤ai≤100000

首先,要互质说明不能有一样的因数,那么我们可以把所有的数先分解因数,然后再从1枚举到m,只要能被这些因数整除的就不是合格的k,我们记录下所有合格k的数量然后从小到大输出即可。

最朴素的暴力做法了,我们想办法优化一下它。

实际上我们不用求出所有的因数的,大的因数可以经由小的因数得到,而且如果一个数不能被小因数整除,那么经由小因数得到的大因数肯定也无法整除这个数,比如2无法整除9,那么经由2得到的4 6 8等肯定也无法整除。所有我们不用求所有的因数,而是去求质因数(因为质因数是无法通过小因数得到的,它是质数啊),那么我们就把所有的数分解质因数,然后通过线性筛,筛掉所有不合格的k即可。如果当前数已经是质数了就不用分解质因数直接线性筛即可。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 100500;
bool mymap[N], prime[N], st[N];
int maxp[N];
int main()
{
    int n, m, x;
    cin >> n >> m;
    maxp[1] = 1;
    for (ll i = 2; i <= N; i++)
    {
        if (st[i])continue;
        for (ll j = i*2; j <= N ; j+=i)
        {
            st[j] = true;
            maxp[j] = i;
        }
        maxp[i] = i;
    }
    for (int i = 0; i < n; i++)
    {
        int x;
        cin >> x;
        if (mymap[x])continue;
        mymap[x] = true;
        while (x != 1)
        {
            prime[maxp[x]] = 1;
            x /= maxp[x];
        }
    }
    vector<int>k;
    k.push_back(1);
    for (int i = 2; i <= m; i++)
    {
        if (prime[i] && !st[i])
            for (int j = i; j <= m; j += i)
                mymap[j] = 1;
    }
    for (int i = 2; i <= m; i++)
        if (!mymap[i])
            k.push_back(i);
    cout << k.size() << endl;
    for (auto i : k)
    {
        cout << i << endl;
    }
    return 0;
}

CodeForces——线段树专题

A - Segment Tree, part 2 - Codeforces

There is an array of n elements, initially filled with zeros. You need to write a data structure that processes two types of queries:

assign value v to all elements on the segment from l to r−1,
find the segment with maximal sum.

Input

The first line contains two numbers n and m (1≤n,m≤100000), the size of the array and the number of operations. The following lines contain the description of the operations. The description of each operation is as follows: l r v: assign the value v to all elements on the interval from l to r−1 (0≤l<r≤n, −109≤v≤109).

Output

Print m lines: the maximum sum of numbers on a segment after each operation. Please note that this segment may be empty (so the sum on it will be equal to 0).

Example

input
5 3
0 5 3
1 3 -1
3 4 -5
output
15
7
3

这题建议去写一下基础版单点修改:A - Segment Tree, part 1 - Codeforces

题目是说给你一个全为0的数组,每次操作给区间l~r的数都改成v,每次修改完后输出当前数组的最大子数组和(也可以一个数都不选,那就是0)。

这种计算最大子段和,我们要维护四个数,一个是从区间左边向右延申得到的最大子段和:lmax,一个数从区间右边向左延申得到的最大子段和rmax,一个是当前区间的最大子段和:date,一个是区间的和:f。

一个区间的最大子段和,要么是左子节点的最大子段和,要么是右子节点的最大子段和,要么是右节点的rmax+左节点的lmax。

一个区间的最大左子段和,要么是左子节点的左子段和,要么是右子节点的左子段和+左节点的区间的和f。

一个区间的最大右子段和,要么是右子节点的右子段和,要么是左子节点的右子段和+右节点的区间和f。

每次修改的时候顺便修改这四个数值即可,最后整个区间的最大子段和就存在date[1]里。

#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>

#define endl '\n';
typedef long long ll;
typedef pair<ll, ll>PII;
const int N = 100500;
const ll NO_OP = 1e18;
ll f[4 * N], b[4 * N], lmax[4 * N], rmax[4 * N], date[4 * N];

void push_down(ll k, ll l, ll r)
{
    if (b[k] != NO_OP)
    {
        int m = (l + r) / 2;
        b[k + k] = b[k];
        b[k + k + 1] = b[k];
        f[k + k] = (m - l + 1) * b[k];
        lmax[k + k] = max((ll)0, f[k + k]);
        rmax[k + k] = max((ll)0, f[k + k]);
        date[k + k] = max((ll)0, f[k + k]);
        f[k + k + 1] = (r - m) * b[k];
        lmax[k + k + 1] = max((ll)0, f[k + k + 1]);
        rmax[k + k + 1] = max((ll)0, f[k + k + 1]);
        date[k + k + 1] = max((ll)0, f[k + k + 1]);
        b[k] = NO_OP;
    }
}

void revise(ll k, ll l, ll r, ll x, ll y, ll v)
{
    if (l == x && r == y)
    {
        b[k] = v;
        f[k] = (r - l + 1) * v;
        date[k] = (r - l + 1) * v;
        lmax[k] = (r - l + 1) * v;
        rmax[k] = (r - l + 1) * v;
        return;
    }
    push_down(k, l, r);
    int m = (l + r) / 2;
    if (y <= m)revise(k + k, l, m, x, y, v);
    else
        if (x > m)revise(k + k + 1, m + 1, r, x, y, v);
        else
        {
            revise(k + k, l, m, x, m, v);
            revise(k + k + 1, m + 1, r, m + 1, y, v);
        }
    f[k] = f[k + k] + f[k + k + 1];
    lmax[k] = max(lmax[k + k], f[k + k] + lmax[k + k + 1]);
    rmax[k] = max(rmax[k + k + 1], f[k + k + 1] + rmax[k + k]);
    date[k] = max(max(date[k + k], date[k + k + 1]), rmax[k + k] + lmax[k + k + 1]);
}

int main()
{
    int n, m;
    cin >> n >> m;
    memset(b, NO_OP, sizeof b);
    while (m--)
    {
        ll x, y, v;
        cin >> x >> y >> v;
        revise(1, 1, n, x + 1, y, v);
        cout << max((ll)0,date[1]) << endl;
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值