20190729

最大值

题意简述

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

$n,q\leq 5\times 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\n",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)\times\gcd\{a_l,a_{l+1},…,a_r\}\}$

$n\leq 10^5,1\leq a_i\leq 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\neq x1$ ,则 $x_1\leq \dfrac{x}{2}$ 。

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

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

时间复杂度 $O(n\times \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\n",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:$

$n\leq 10^{10^6},m,k\leq 10^6$  。

不会推式子了。

$$Ans=\sum_{i=0}^n \dbinom{n}{i}\times [i^k-(n-i)^k]^2\\=\sum_{i=0}^{[\frac{n}{m}]}\sum_{j=0}^{n\mod m} \dbinom{n}{i\times m+j}\times [i^k-(n-i)^k]^2\\=\sum_{i=0}^{[\frac{n}{m}]}\dbinom{[\frac{n}{m}]}{i}\sum_{j=0}^{n\mod m}\dbinom{n\mod m}{j}\times [i^k-(n-i)^k]^2\\=2^{[\frac{n}{m}]\mod (mod-1)}\sum_{j=0}^{n\mod m}\times [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\n",Sum%mod);return 0;
}
View Code

 

posted @ 2019-07-29 20:10  siruiyang_sry  阅读(223)  评论(0编辑  收藏  举报