3月之从零开始的ACM

2020.3
3.19
学习ST表,处理区间求最值。
对于f[i][j]为从i开始的2^j个数中的最值,那么终点为i + 2^j -1,区间长度为2^j 。
对于一个区间[l,r],首先求出区间长度k=log2(r-l+1) 。
那么区间最值由[l,l+2^k-1] 及 [ r-2^k+1,r] 保证一定可以覆盖查询的区间。

//f[i][0]为自己。
//松弛区间
for(int j=1;j<=21;j++)
	for(int i=1;i+(1<<j)-1<=n;i++)
		f[i][j]=max(f[i][j-1],f[i+(1<<(j-1))][j-1]);
//询问区间
ll l=read(),r=read();
ll k=log2(r-l+1);
cout<<max(f[l][k],f[r+1-(1<<k)][k])<<"\n";         

3.20
学习乘法逆元,假设有p=ki+r:
取模意义下: k
i + r mod p == 0
乘上i^(-1) 以及r^(-1) :i^(-1)= - k*r^(-1)
代换: i^(-1) = ( - (p/i) * (p%i)^(-1) ) %p
有: i^(-1) = (p-(p/i) *(p%i)^(-1) )%p
其中inv[1]=1

inv[1]=1;
for(int i=2;i<=n;i++)
	inv[i]=((p-p/i)*inv[p%i])%p;

3.21
学习卢卡斯定理,处理组合数取模的问题。
Lucas(n,m,p)=C(n%p,m%p,p)×Lucas( n/p,m/p,p)%p
其中Lucas(n,0,p)=1

ll Inv(ll x,ll p){return qp(x,p-2,p);}
ll Cal(ll n,ll m,ll p){
    if(m>n) return 0;
    ll ans=1;
    for(int i=1;i<=m;++i)ans=ans*Inv(i,p)%p*(n-i+1)%p;
    return ans%p;
}
ll Lucas(ll n,ll m,ll p){
    if(!m) return 1;
    return Cal(n%p,m%p,p)*Lucas(n/p,m/p,p)%p;
}

学习单调队列,处理滑动窗口最值问题。
当q[head]+m<=i说明队首元素已经跟不上滑动窗口。
当a[ q[tail] ]<a[i]说明队尾元素比当前元素小,失去优先级。

for(int i=1;i<=n;i++){
	while(head<=tail&&q[head]+m<=i) ++head;
	while(head<=tail&&a[q[tail]]<a[i]) --tail;
	q[++tail]=i;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章