牛客2021年七夕节比赛大部分题解(因数枚举模板线段树dp……)

Posted hans774882968

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了牛客2021年七夕节比赛大部分题解(因数枚举模板线段树dp……)相关的知识,希望对你有一定的参考价值。

传送门

偶然刷到了,就做了一下。F是防AK,不会,ACDE水,略。

比较有参考价值的是I题,dp。

B

一开始想的是状压枚举素数集合,但是各素因子的幂不一定要统一。于是改成了直接dfs枚举所有素数的所有幂次,并逐一判定。

写完了一发AC了以后才发现,枚举所有素数的所有幂次也就是枚举所有因数,23333我是sb。不过这个枚举方法肯定比根号枚举要快一点。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)

const int N = 32000 + 5;

int n;bool vis[N];vector<int> primes;

void dbg()puts("");
template<typename T, typename... R>void dbg(const T &f, const R &... r) 
    cout << f << " ";
    dbg(r...);

template<typename Type>inline void read(Type &xx)
    Type f = 1;char ch;xx = 0;
    for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
    for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
    xx *= f;

void read()
template<typename T,typename ...R>void read(T &x,R &...r)
    read(x);
    read(r...);


void init_p(int m)
    vis[1] = true;
    rep(i,2,m)
        if(!vis[i]) primes.push_back(i);
        for(int p: primes)
            if(i > m / p) break;
            vis[i * p] = true;
            if(i % p == 0) break;
        
    


void dfs(vector<vector<int> > &vec,int &ans,int dep = 0,int mul = 1)
    if(dep >= vec.size())
        if(mul == 1) return;
        int x = n;while(x % mul == 0) x /= mul;
        if(x < mul) ans = min(ans,mul);
        return;
    
    int p = vec[dep][0];
    for(int cur = 1;;cur *= p)
        dfs(vec,ans,dep+1,mul*cur);
        if(cur == vec[dep][1]) break;
    


int solve()
    int x = n;
    vector<vector<int> > vec;
    for(int p: primes)
        if(p > x/p) break;
        int pw = 1;
        while(x % p == 0)
            x /= p;
            pw *= p;
        
        if(pw > 1) vec.push_back(p,pw);
    
    if(x > 1) vec.push_back(x,x);
    int ans = n;
    dfs(vec,ans);
    return ans;


int main(int argc, char** argv) 
    init_p(N-5);
    int T;read(T);
    while(T--)
        read(n);
        printf("%d\\n",solve());
    
    return 0;

G

或运算有如下单调性:两个集合是子集关系,则子集的or值小于等于超集的or值。所以这题相当于询问区间或,以及区间赋值。套线段树模板。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)
#define ls(x) ((x) << 1)
#define rs(x) ((x) << 1 | 1)

const int N = 1e6 + 5;

int n,m,a[N];

void dbg()puts("");
template<typename T, typename... R>void dbg(const T &f, const R &... r) 
    cout << f << " ";
    dbg(r...);

template<typename Type>inline void read(Type &xx)
    Type f = 1;char ch;xx = 0;
    for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
    for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
    xx *= f;

void read()
template<typename T,typename ...R>void read(T &x,R &...r)
    read(x);
    read(r...);


struct Nodeint sum,tg;nd[N<<2];

void pushup(int x)nd[x].sum = nd[ls(x)].sum | nd[rs(x)].sum;
void pushdown(int x)
    int tg = nd[x].tg;
    if(!tg) return;
    nd[ls(x)].tg = nd[rs(x)].tg = nd[ls(x)].sum = nd[rs(x)].sum = tg;
    nd[x].tg = 0;


void build(int l,int r,int x)
    if(l == r)
        nd[x] = a[l],0;return;
    
    int mid = (l+r)>>1;
    build(l,mid,ls(x));
    build(mid+1,r,rs(x));
    pushup(x);


void mdy(int ql,int qr,int v,int l = 1,int r = n,int x = 1)
    if(ql <= l && r <= qr)
        nd[x] = v,v;return;
    
    pushdown(x);
    int mid = (l+r)>>1;
    if(ql <= mid) mdy(ql,qr,v,l,mid,ls(x));
    if(qr > mid) mdy(ql,qr,v,mid+1,r,rs(x));
    pushup(x);


int qry(int ql,int qr,int l = 1,int r = n,int x = 1)
    if(ql <= l && r <= qr) return nd[x].sum;
    pushdown(x);
    int mid = (l+r)>>1,ans = 0;
    if(ql <= mid) ans |= qry(ql,qr,l,mid,ls(x));
    if(qr > mid) ans |= qry(ql,qr,mid+1,r,rs(x));
    return ans;


int main(int argc, char** argv) 
    read(n,m);
    rep(i,1,n) read(a[i]);
    build(1,n,1);
    while(m--)
        int op;read(op);
        if(op == 1)
            int l,r;read(l,r);
            printf("%d\\n",qry(l,r));
        
        else
            int l,r,x;read(l,r,x);
            mdy(l,r,x);
        
    
    return 0;

H

这题给定的线段,其实是一个特殊的有向图。之前某场abc考了一个有向图最短路的问题,就是在边权的基础上加了一个特性:某个节点a秒开启b秒关闭,无限交替。这个问题的关键性质就是:立刻走不会比”等一会再走“更差

利用这个性质随便模拟一下就可以过了。判定是否要等待:

int tmp = ans % (pt[i].a + pt[i].b);
if(tmp < pt[i].a) ans += pt[i].a - tmp;

注意:别忘了先对位置升序排序。

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
#define rep(i,a,b) for(int i = (a);i <= (b);++i)
#define re_(i,a,b) for(int i = (a);i < (b);++i)
#define dwn(i,a,b) for(int i = (a);i >= (b);--i)

const int N = 1e5 + 5;

int n,m;

void dbg()puts("");
template<typename T, typename... R>void dbg(const T &f, const R &... r) 
    cout << f << " ";
    dbg(r...);

template<typename Type>inline void read(Type &xx)
    Type f = 1;char ch;xx = 0;
    for(ch = getchar();ch < '0' || ch > '9';ch = getchar()) if(ch == '-') f = -1;
    for(;ch >= '0' && ch <= '9';ch = getchar()) xx = xx * 10 + ch - '0';
    xx *= f;

void read()
template<typename T,typename ...R>void read(T &x,R &...r)
    read(x);
    read(r...);


struct Nodeint p,a,b;pt[N];
bool cmp(Node &x,Node &y)return x.p 以上是关于牛客2021年七夕节比赛大部分题解(因数枚举模板线段树dp……)的主要内容,如果未能解决你的问题,请参考以下文章

牛客网_2018年全国多校算法寒假训练营练习比赛(第一场)_部分题解

《牛客2021年儿童节比赛D》

牛客白月赛15题解

2022牛客寒假算法基础集训营 5 全部题解

2022牛客寒假算法基础集训营 5 全部题解

2020-2021年度第二届全国大学生算法设计与编程挑战赛(春季赛)部分题题解