20230401 模拟赛题解
A
根据树是连通图的性质,答案为 \(\dfrac{n(n-1)}{2}\)。
B
注意到操作是 \(\div 2\),每个数操作不超过 \(\log|V|\) 次。于是大于 \(n\log|V|\) 的询问答案为 \(0\)。剩下的询问可以离线从小到大排序,用优先队列模拟操作。每次询问在前一次的询问基础上执行尚未执行的操作次数。最终得到的堆顶即为答案。
时间复杂度 \(\mathcal{O}(q\log n\cdot \log|V|)\),空间复杂度 \(\mathcal{O}(n)\)。
点击查看代码
#include<bits/stdc++.h>
#define N 200005 
using namespace std;
int n,q,ans[N];
pair<int,int>g[N];
priority_queue<int>pq;
int main() {
	scanf("%d%d",&n,&q);
	for(int i=1,x;i<=n;++i){
		scanf("%d",&x);
		pq.push(x);
	}
	for(int i=1;i<=q;++i){
		scanf("%d",&g[i].first);
		g[i].second=i;
	}
	sort(g+1,g+1+q);
	for(int i=1;i<=q;++i){
		if(g[i].first<=31*n){
			for(int j=g[i-1].first+1;j<=g[i].first;++j){
				pq.push(pq.top()/2);
				pq.pop();
			}
			ans[g[i].second]=pq.top();
		}else{
			break;
		}
	}
	for(int i=1;i<=q;++i){
		printf("%d\n",ans[i]);
	}
	return 0;
}
C
设 \(f_i\) 为 \(\prod\limits_{j=1}^ia_j^{b_j}\) 的约数和。有:
\[f_i=\begin{cases}1,i=0\\f_{i-1}\times \sum\limits_{j=0}^{b_i}a_i^j,\text{otherwise}\end{cases}
\]
解释一下。\(a_i\) 的指数可以取 \(0\sim b_i\),每一种取值都可以和 \(a_1\sim a_{i-1}\) 中的所有方案组合。才有了第二个式子。
计算幂次之和可以用公式。但是我用了一些奇奇怪怪的方法使数据不存在逆元。所以可以分治。也可以矩阵快速幂,但是超纲了。
时间复杂度 \(\mathcal{O}(n\log^2|V|)\),空间复杂度 \(\mathcal{O}(n)\)。
点击查看代码
#include<bits/stdc++.h>
#define N 200005
#define int long long
using namespace std;
int n,m,a[N],b[N],f[N];
int ksm(int x,int p){
	int ret=1;
	while(p){
		if(p&1){
			ret=ret*x%m;
		}
		x=x*x%m;
		p>>=1;
	}
	return ret;
}
int divide(int x,int l,int r){
	if(l==r){
		return 1;
	}
	int mid=(l+r)>>1;
	if(!((r-l+1)&1)){
		return divide(x,l,mid)*(ksm(x,mid-l+1)+1)%m;
	}else{
		if(mid-l+1>r-mid){
			--mid;
		}
		return (divide(x,l,mid)*(ksm(x,mid-l+1)+1)%m+ksm(x,r))%m;
	}
}
signed main(){
	scanf("%lld%lld",&n,&m);
	for(int i=1;i<=n;++i){
		scanf("%lld%lld",a+i,b+i);
	}
	f[0]=1;
	for(int i=1;i<=n;++i){
		f[i]=f[i-1]*divide(a[i],0,b[i])%m;
	}
	printf("%lld",f[n]);
}

 
                
            
         浙公网安备 33010602011771号
浙公网安备 33010602011771号