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 */
最大公约数
题意简述
对于长度为 $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; }
小 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; }