zoukankan      html  css  js  c++  java
  • 20190729

    最大值

    题意简述

    维护一个数据结构满足,区间增加一个等差数列,区间求最值。

    $n,qleq 5 imes 10^4$ 。

    $solution:$

    李超线段树模板,对于每一个线段树节点维护一条线段,运用标记永久化查询答案。

    当新添加的线段 $y=kx+b$ 与线段树中的线段 $y=Kx+B$ 比较时,直接去比较哪一个对 $[l,r]$ 贡献较长,将贡献较少的下传的对应的 左/右子树中。

    这样对于 $log n$ 个区间增加,单次修改时间复杂度最大为 $O(log^2 n)$ 。

    查询最值时间复杂度依然为 $O(log n)$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #include<climits>
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=300001;
    struct Line{
        int k,b;
        Line(){k=0,b=INT_MIN;}
        Line(int _k,int _b){k=_k,b=_b;}
        int Q(int x){return x*k+b;}
    }g[MAXN<<2];
    struct Segment{
        int Maxn[MAXN<<2];
        void Modify(int k,int l,int r,int x,int y,Line w){
            Maxn[k]=max(Maxn[k],max(w.Q(max(l,x)),w.Q(min(r,y))));
            if(x<=l&&r<=y){
                Maxn[k]=max(Maxn[k],max(w.Q(l),w.Q(r)));
                if(w.k==g[k].k){
                    if(w.k>=0) g[k].b=max(w.b,g[k].b);
                    else g[k].b=min(w.b,g[k].b);
                    return;
                }
                int mid=l+r>>1;
                if(w.Q(mid)>g[k].Q(mid)) swap(g[k],w);
                if(l==r) return;
                if(w.k<g[k].k) Modify(k<<1,l,mid,x,y,w);
                else Modify(k<<1|1,mid+1,r,x,y,w);
                return;
            }
            int mid=l+r>>1;
            if(x<=mid) Modify(k<<1,l,mid,x,y,w);
            if(mid<y) Modify(k<<1|1,mid+1,r,x,y,w);
            return;
        }
        int Query(int k,int l,int r,int x,int y){
            if(x<=l&&r<=y) return Maxn[k];
            int mid=l+r>>1,res=max(g[k].Q(max(l,x)),g[k].Q(min(r,y)));
            if(x<=mid) res=max(res,Query(k<<1,l,mid,x,y));
            if(mid<y) res=max(res,Query(k<<1|1,mid+1,r,x,y));
            return res;
        }
    }segment;
    int n,m;
    int main(){
        freopen("max.in","r",stdin);
        freopen("max.out","w",stdout);
        n=read(),m=read();
        for(int i=1;i<=n;i++) segment.Modify(1,1,n,i,i,Line(0,read()));
        for(int i=1;i<=m;i++){
            int opt=read();
            if(opt==1){
                int l=read(),r=read(),k=read(),b=read();
                segment.Modify(1,1,n,l,r,Line(k,b-l*k));
            }else{
                int l=read(),r=read();
                printf("%d
    ",segment.Query(1,1,n,l,r));
            }
        }return 0;
    }/*
    5 2
    2 1 4 5 4 
    1 2 5 2 1
    2 3 5
    */
    View Code

    最大公约数

    题意简述

    对于长度为 $n$ 的序列 $a$ ,求 $max{(r-l+1) imesgcd{a_l,a_{l+1},…,a_r}}$

    $nleq 10^5,1leq a_ileq 10^{12}$ 。

    $solution:$

    降智好题。

    考虑对于 $x=gcd{a_l,a_{l+1},…,a_r}$ ,若 $x_1=gcd{a_{l-1},a_l,a_{l+1},…,a_r},x eq x1$ ,则 $x_1leq dfrac{x}{2}$ 。

    所以对于枚举右端点,出现的 $gcd$ 个数不会超过 $log_2 10^{12}$ 。

    而对于相同的元素只要维护最左端,因为 $gcd$ 个数很小直接暴力维护即可。

    时间复杂度 $O(n imes log_2 10^{12})$ 。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define int long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=100001;
    int T,n,a[MAXN],g[MAXN],val[MAXN],ps[MAXN],las,cnt,Maxn,tot;
    int gcd(int a,int b){
        if(!b) return a;
        return gcd(b,a%b);
    }
    void solve(){
        tot=0,Maxn=0;
        n=read();
        for(int i=1;i<=n;i++) a[i]=read();
        for(int i=1;i<=n;i++){
            las=tot,tot=0;
            for(int j=1;j<=las;j++){
                int Ans=gcd(val[j],a[i]);
                if(val[tot]!=Ans) val[++tot]=Ans,ps[tot]=ps[j],Maxn=max(Maxn,Ans*(i-ps[j]+1));
            } 
            if(val[tot]!=a[i]) val[++tot]=a[i],ps[tot]=i,Maxn=max(Maxn,a[i]);
        }printf("%lld
    ",Maxn);return;
    }
    
    signed main(){
        freopen("gcd.in","r",stdin);
        freopen("gcd.out","w",stdout);
        T=1;
        while(T--) solve();
        return 0;
    }
    View Code

    小 Q 的集合

    $solution:$

    $nleq 10^{10^6},m,kleq 10^6$  。

    不会推式子了。

    $$Ans=sum_{i=0}^n dbinom{n}{i} imes [i^k-(n-i)^k]^2\=sum_{i=0}^{[frac{n}{m}]}sum_{j=0}^{nmod m} dbinom{n}{i imes m+j} imes [i^k-(n-i)^k]^2\=sum_{i=0}^{[frac{n}{m}]}dbinom{[frac{n}{m}]}{i}sum_{j=0}^{nmod m}dbinom{nmod m}{j} imes [i^k-(n-i)^k]^2\=2^{[frac{n}{m}]mod (mod-1)}sum_{j=0}^{nmod m} imes [i^{k}-(n-i)^{k}]^2 $$

    直接暴力即可。

    #include<iostream>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    #define int long long
    using namespace std;
    inline int read(){
        int f=1,ans=0;char c=getchar();
        while(c<'0'||c>'9'){if(c=='-')f=-1;c=getchar();}
        while(c>='0'&&c<='9'){ans=ans*10+c-'0';c=getchar();}
        return f*ans;
    }
    const int MAXN=1000011;
    char str[MAXN];
    int k,mod,len,N,nm,res,fac[MAXN],inv[MAXN],Ifac[MAXN];
    inline int Mod(int x){return ((x%mod)+mod)%mod;}
    inline int ksm(int a,int b){
        int ans=1;
        while(b){
            if(b&1) ans*=a,ans%=mod;
            a*=a,a%=mod;
            b>>=1;
        }return ans;
    }
    int Sum,P,pw[MAXN];
    inline int C(int a,int b){return (((fac[a]*Ifac[a-b])%mod)*Ifac[b])%mod;}
    signed main(){
        freopen("set.in","r",stdin);
        freopen("set.out","w",stdout);
        scanf("%s",str+1);k=read(),mod=read();
        len=strlen(str+1);
        for(register int i=1;i<=len;i++){
            N=(N*10+(str[i]-'0'))%mod;
            res=res*10+str[i]-'0';
            nm=(nm*10+(int)(res/mod))%(mod-1);
            res%=mod;
        }
        fac[0]=1;for(register int i=1;i<=N;++i) fac[i]=fac[i-1]*i,fac[i]%=mod;
        inv[1]=1;for(register int i=2;i<=N;++i) inv[i]=(mod-mod/i)*inv[mod%i],inv[i]%=mod;
        Ifac[0]=1;for(register int i=1;i<=N;++i) Ifac[i]=Ifac[i-1]*inv[i],Ifac[i]%=mod;
        for(int i=1;i<=N;i++) pw[i]=ksm(i,k);
        for(register int i=0;i<=N;++i){
            P=Mod(pw[i]-pw[N-i]);
            Sum+=(((C(N,i)*P)%mod)*P)%mod;Sum%=mod;
        }
        Sum*=ksm(2,nm);Sum%=mod;
        printf("%lld
    ",Sum%mod);return 0;
    }
    View Code
  • 相关阅读:
    Linux Virtual Server技术
    log4j+slf4j迁移到log4j2+slf4j (Servlet3.0)
    Android控件ToggleButton的使用方法
    Redis学习手冊(事务)
    游戏server之server优化思路
    Codeforces 474D Flowers (线性dp 找规律)
    【C语言】编写函数实现库函数atof
    unity3D游戏开发实战原创视频讲座系列7之消消乐游戏开发
    [WebGL入门]二十一,从平行光源发出的光
    TwoSum leetcode
  • 原文地址:https://www.cnblogs.com/si-rui-yang/p/11265997.html
Copyright © 2011-2022 走看看