• 牛客练习赛26游记


    牛客练习赛26游记

    A-平面

    题目大意:

    在平面上画(n(nle10^9))个X,最多将平面分成几部分?

    思路:

    如果是画直线的话答案是(frac{n^2+n+2}2)

    画X相当于画两条直线,因此答案是(2n^2+n+1)

    时间复杂度(mathcal O(1))

    源代码:

    #include<cstdio>
    #include<cctype>
    inline int getint() {
        register char ch;
        while(!isdigit(ch=getchar()));
        register int x=ch^'0';
        while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
        return x;
    }
    typedef long long int64;
    int main() {
        const int n=getint()*2;
        printf("%lld
    ",((int64)n*n+n+2)/2);
        return 0;
    }
    

    B-烟花

    题目大意:

    (n(nle10^5))个烟花,每个烟花代表着互不相同的颜色,对于第(i)个烟花,它有(p_i)的概率被成功点燃。求产生颜色的期望个数及产生恰好(k(kle200))种颜色的概率。

    思路:

    显然期望个数就是(sum p_i)

    而产生恰好(k)种颜色的概率可以DP。

    (f_{i,j})表示前(i)个烟花中成功点燃(j)个的概率,转移方程为(f_{i,j}=f_{i-1,j-1} imes p_i+f_{i-1,j} imes(1-p_i))

    时间复杂度(mathcal O(nk))

    源代码:

    #include<cstdio>
    #include<cctype>
    inline int getint() {
        register char ch;
        while(!isdigit(ch=getchar()));
        register int x=ch^'0';
        while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
        return x;
    }
    const int N=1e5+1,M=201;
    double p[N],f[N][M];
    int main() {
        const int n=getint(),m=getint();
        for(register int i=1;i<=n;i++) {
            scanf("%lf",&p[i]);
        }
        f[0][0]=1;
        for(register int i=1;i<=n;i++) {
            f[i][0]=f[i-1][0]*(1-p[i]);
            for(register int j=1;j<=m;j++) {
                f[i][j]=f[i-1][j]*(1-p[i])+f[i-1][j-1]*p[i];
            }
        }
        double ans=0;
        for(register int i=1;i<=n;i++) ans+=p[i];
        printf("%.4f
    %.4f
    ",ans,f[n][m]);
        return 0;
    }
    

    C-城市规划

    题目大意:

    有一条(n(nle10^6))个点的链,各结点编号依次为(1sim n)。另有(m(mle10^7))个限制((x_i,y_i)),要求你从链上去掉一些边,使得对于所有的限制,(x_i)(y_i)均不连通。求最少删掉几条边。

    思路:

    如果我们假设结点(1,2)之间的边编号为(2)(2,3)之间的边编号为(3)。将约束条件从点转化成边,则([x_i+1,y_i])之间一定有边要被删掉。

    方便起见,下面我们用(x_i)表示前面的(x_i+1)

    对于每个(y_i)只保留最大的(x_i)

    从左往右扫一遍,记录删去的最右的边(p)。如果当前点是某个(y_i),且对应的(x_ile p),说明(x_isim y_i)之间已经不连通了,这时不需要进行任何操作。如果(x_i>p),则将(x_i)作为新的(p)ans++即可。

    时间复杂度(mathcal O(n+m)),但是比较卡常。

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    #include<sys/mman.h>
    #include<sys/stat.h>
    class MMapInput {
        private:
            char *buf,*p;
            int size;
        public:
            MMapInput() {
                register int fd=fileno(stdin);
                struct stat sb;
                fstat(fd,&sb);
                size=sb.st_size;
                buf=reinterpret_cast<char*>(mmap(0,size,PROT_READ,MAP_PRIVATE,fileno(stdin),0));
                p=buf;
            }
            char getchar() {
                return (p==buf+size||*p==EOF)?EOF:*p++;
            }
    };
    MMapInput mmi;
    inline int getint() {
        register char ch;
        while(!isdigit(ch=mmi.getchar()));
        register int x=ch^'0';
        while(isdigit(ch=mmi.getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
        return x;
    }
    const int N=1e6+1;
    int cnt[N],left[N];
    int main() {
        const int n=getint(),m=getint();
        for(register int i=0;i<m;i++) {
            const int b=getint()+1,e=getint();
            left[e]=std::max(left[e],b);
        }
        int ans=0;
        for(register int i=1,p=0;i<=n;i++) {
            if(p<left[i]) {
                ans++;
                p=i;
            }
        }
        printf("%d
    ",ans);
        return 0;
    }
    

    D-xor序列

    题目大意:

    一个长度为(n(nle10^5))的数列,(q(qle10^5))次询问,每次询问(x)能否通过与数列中的一些数进行异或运算使得最终结果为(y)

    思路:

    线性基。

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<algorithm>
    inline int getint() {
        register char ch;
        while(!isdigit(ch=getchar()));
        register int x=ch^'0';
        while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
        return x;
    }
    const int N=32;
    int b[N];
    int main() {
        const int n=getint();
        for(register int i=0;i<n;i++) {
            int x=getint();
            for(register int i=N-1;~i;i--) {
                if(!(x&(1ll<<i))) continue;
                if(!b[i]) {
                    b[i]=x;
                    break;
                } else {
                    x^=b[i];
                }
            }
        }
        const int m=getint();
        for(register int i=0;i<m;i++) {
            int x=getint()^getint();
            for(register int i=N-1;~i;i--) {
                if(x>>i&1) x^=b[i];
            }
            puts(x==0?"YES":"NO");
        }
        return 0;
    }
    

    E-树上路径

    题目大意:

    给出一个(n)个点的树,(1)号节点为根节点,每个点有一个权值。(m(mle10^5))次操作,操作包含以下(3)种:

    1. 将以(x)为根的子树内节点的权值加(val)
    2. ((x,y))路径上的节点权值加(val)
    3. 询问((x,y))路径上节点的权值两两相乘的和。

    思路:

    首先考虑数列上的情况,对于区间([l,r])。若我们记(a)([l,r])的和,(b)([l,r])的平方和,则答案为(frac{a^2-b}2)

    可以使用线段树来维护,利用树链剖分将这种做法推广到树上。

    时间复杂度(mathcal O(mlog^2 n))

    源代码:

    #include<cstdio>
    #include<cctype>
    #include<vector>
    inline int getint() {
        register char ch;
        while(!isdigit(ch=getchar()));
        register int x=ch^'0';
        while(isdigit(ch=getchar())) x=(((x<<2)+x)<<1)+(ch^'0');
        return x;
    }
    using int64=long long;
    const int N=1e5+1,mod=1e9+7,inv=5e8+4;
    int w[N],par[N],top[N],dep[N],size[N],son[N],dfn[N],id[N];
    std::vector<int> e[N];
    inline void add_edge(const int &u,const int &v) {
        e[u].emplace_back(v);
        e[v].emplace_back(u);
    }
    void dfs(const int &x,const int &par) {
        size[x]=1;
        ::par[x]=par;
        dep[x]=dep[par]+1;
        for(auto &y:e[x]) {
            if(y==par) continue;
            dfs(y,x);
            size[x]+=size[y];
            if(size[y]>size[son[x]]) {
                son[x]=y;
            }
        }
    }
    void dfs(const int &x) {
        dfn[x]=++dfn[0];
        id[dfn[x]]=x;
        top[x]=x==son[par[x]]?top[par[x]]:x;
        if(son[x]) dfs(son[x]);
        for(auto &y:e[x]) {
            if(y==par[x]||y==son[x]) continue;
            dfs(y);
        }
    }
    class SegmentTree {
        #define _left <<1
        #define _right <<1|1
        #define mid ((b+e)>>1)
        private:
            int tag[N<<2],sum[N<<2],ssum[N<<2];
            void update(const int &p,const int &b,const int &e,const int &x) {
                (tag[p]+=x)%=mod;
                ssum[p]=((ssum[p]+(int64)x*x%mod*len(b,e)%mod)%mod+(int64)2*sum[p]%mod*x%mod)%mod;
                sum[p]=(sum[p]+(int64)x*len(b,e))%mod;
            }
            void push_up(const int &p) {
                sum[p]=(sum[p _left]+sum[p _right])%mod;
                ssum[p]=(ssum[p _left]+ssum[p _right])%mod;
            }
            void push_down(const int &p,const int &b,const int &e) {
                if(!tag[p]) return;
                update(p _left,b,mid,tag[p]);
                update(p _right,mid+1,e,tag[p]);
                tag[p]=0;
            }
            inline int len(const int &b,const int &e) const {
                return e-b+1;
            }
        public:
            void build(const int &p,const int &b,const int &e) {
                tag[p]=0;
                if(b==e) {
                    sum[p]=w[id[b]];
                    ssum[p]=(int64)w[id[b]]*w[id[b]]%mod;
                    return;
                }
                build(p _left,b,mid);
                build(p _right,mid+1,e);
                push_up(p);
            }
            void modify(const int &p,const int &b,const int &e,const int &l,const int &r,const int &x) {
                if(b==l&&e==r) {
                    update(p,b,e,x);
                    return;
                }
                push_down(p,b,e);
                if(l<=mid) modify(p _left,b,mid,l,std::min(mid,r),x);
                if(r>mid) modify(p _right,mid+1,e,std::max(mid+1,l),r,x);
                push_up(p);
            }
            std::pair<int,int> query(const int &p,const int &b,const int &e,const int &l,const int &r) {
                if(b==l&&e==r) {
                    return std::make_pair(sum[p],ssum[p]);
                }
                int ret0=0,ret1=0;
                push_down(p,b,e);
                if(l<=mid) {
                    const auto q=query(p _left,b,mid,l,std::min(mid,r));
                    (ret0+=q.first)%=mod;
                    (ret1+=q.second)%=mod;
                }
                if(r>mid) {
                    const auto q=query(p _right,mid+1,e,std::max(mid+1,l),r);
                    (ret0+=q.first)%=mod;
                    (ret1+=q.second)%=mod;
                }
                return std::make_pair(ret0,ret1);
            }
        #undef _left
        #undef _right
        #undef mid
    };
    SegmentTree t;
    inline int query(int x,int y) {
        int ret0=0,ret1=0;
        while(top[x]!=top[y]) {
            if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
            const auto q=t.query(1,1,dfn[0],dfn[top[x]],dfn[x]);
            (ret0+=q.first)%=mod;
            (ret1+=q.second)%=mod;
            x=par[top[x]];
        }
        if(dep[x]<dep[y]) std::swap(x,y);
        const auto q=t.query(1,1,dfn[0],dfn[y],dfn[x]);
        (ret0+=q.first)%=mod;
        (ret1+=q.second)%=mod;
        return ((int64)ret0*ret0%mod-ret1+mod)%mod;
    }
    inline void modify(int x,int y,const int &val) {
        while(top[x]!=top[y]) {
            if(dep[top[x]]<dep[top[y]]) std::swap(x,y);
            t.modify(1,1,dfn[0],dfn[top[x]],dfn[x],val);
            x=par[top[x]];
        }
        if(dep[x]<dep[y]) std::swap(x,y);
        t.modify(1,1,dfn[0],dfn[y],dfn[x],val);
    }
    int main() {
        const int n=getint(),m=getint();
        for(register int i=1;i<=n;i++) w[i]=getint();
        for(register int i=1;i<n;i++) {
            add_edge(getint(),getint());
        }
        dfs(1,0);
        dfs(1);
        t.build(1,1,n);
        for(register int i=0;i<m;i++) {
            const int opt=getint();
            if(opt==1) {
                const int x=getint(),val=getint();
                t.modify(1,1,n,dfn[x],dfn[x]+size[x]-1,val);
            }
            if(opt==2) {
                const int x=getint(),y=getint(),val=getint();
                modify(x,y,val);
            }
            if(opt==3) {
                const int x=getint(),y=getint();
                printf("%d
    ",(int64)query(x,y)*inv%mod);
            }
        }
        return 0;
    }
    
  • 相关阅读:
    WHU 1572 Cyy and Fzz (AC自动机 dp )
    Codeforces 441D Valera and Swaps(置换群)
    Codeforces 527E Data Center Drama(欧拉回路)
    差分约束小结
    Codeforces 193D Two Segments 解题报告
    SGU 231.Prime Sum
    SGU 249.Matrix(Gray码)
    SGU 222.Little Rooks
    SGU 207.Robbers
    risc-v的寻址模式
  • 原文地址:https://www.cnblogs.com/skylee03/p/9607523.html
Copyright © 2020-2023  润新知