题解 CF2053D Refined Product Optimality

【洛谷专栏】

复活后的第一篇题解和比赛。

感觉这是一个很有意思的题。

题意

有两个长度为 n 的序列 a,b

q 次修改,每次修改给出两个整数 o,x

  • o=1 时,axax+1
  • o=2 时,bxbx+1

pb 的一种排列,在第一次修改前和每次修改后,你需要求出所有满足条件的 pi=1nmin(ai,pi) 的最大值。

由于答案可能很大,所以对 998244353 取模。

分析

不难证明,最大值即为将 a,b 升序排列后所求的值。

简单证明一下,假设 a1<a2,b1<b2,那么 min(a1,b2)×min(a2,b1)min(a1,b1)×min(a2,b2),所以降序排列会使答案变得更劣。

于是就可以在 O(nlogn) 的时间复杂度内求出修改前答案的值,接下来考虑修改操作。

修改只会修改一个,也只会增加 1 的值,所以对答案的影响并不会很大。

修改的时候如果要调整序列来维持单调性是一件很麻烦的事情。假设我们修改的是 ax,只需要在排序的序列中修改最后一个值为 ax 的位置,就不会影响其单调性。

于是求出这个位置后,可以撤销该位置对答案原有的贡献,乘上该位置的逆元,然后修改后再将贡献加入进去即可。

以上操作就可以用二分和快速幂解决,修改 b 序列的情况同理。

总体时间复杂度为 O(nlogn+qlogn)

代码

//the code is from chenjh
#include<bits/stdc++.h>
#define MAXN 200002
using namespace std;
typedef long long LL;
constexpr int mod=998244353;
int n,q;
int qpow(int a,int b=mod-2){
	int ret=1;
	for(;b;b>>=1,a=(LL)a*a%mod)if(b&1)ret=(LL)ret*a%mod;
	return ret%mod;
}
int a[MAXN],b[MAXN],c[MAXN],d[MAXN];//c,d 序列表示排序后的 a,b 序列。
void solve(){
	cin>>n>>q;
	for(int i=1;i<=n;i++) cin>>a[i],c[i]=a[i];
	for(int i=1;i<=n;i++) cin>>b[i],d[i]=b[i];
	sort(c+1,c+n+1),sort(d+1,d+n+1);
	int ans=1;
	for(int i=1;i<=n;i++) ans=(LL)ans*min(c[i],d[i])%mod;
	cout<<ans<<' ';
	for(int o,x,p;q--;){
		cin>>o>>x;
		p=0;
		if(o==1)
			p=upper_bound(c+1,c+n+1,a[x])-c-1,//找到第一个大于 a_x 的位置的前一个,即最后一个等于 a_x 的位置。
			ans=(LL)ans*qpow(min(c[p],d[p]))%mod,//除以这个数,即乘这个数的逆元。
			++a[x],++c[p];//对这些位置进行修改。
		else if(o==2)
			p=upper_bound(d+1,d+n+1,b[x])-d-1,//b 序列同理。
			ans=(LL)ans*qpow(min(c[p],d[p]))%mod,
			++b[x],++d[p];
		ans=(LL)ans*min(c[p],d[p])%mod;//乘上修改后这个位置的贡献。
		cout<<ans<<' ';
	}
	cout<<'\n';
}
int main(){
	ios::sync_with_stdio(false),cin.tie(nullptr);
	int T;cin>>T;
	while(T--) solve(); 
	return 0;
}
posted @   Chen_Jinhui  阅读(1)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现

一言

翻涌的银河,现在在此化作怒涛之光现出身姿吧!
——游戏王zexal
点击右上角即可分享
微信分享提示