Gushing over Pro|

BigSmall_En

园龄:3年2个月粉丝:3关注:5

2022-09-04 21:58阅读: 58评论: 0推荐: 0

CF1322C Instant Noodles 题解

CF1322C Instant Noodles

  • \(t\) 组测试数据。
  • 给出一张点数为 \(2N\) 的二分图,其中右侧的第 \(i\) 个点有点权为 \(c_i\)
  • \(S\) 表示左侧点的一个非空点集,设 \(f(S)\) 表示右侧点中至少与 \(S\) 中一个点相连的点的点权和。
  • 请你求出,对于所有非空集合 \(S\)\(f(S)\)\(\gcd\) 为多少。
  • \(1 \leq t,\sum n,\sum m \leq 5\times 10^5\)\(1 \leq c_i \leq 10^{12}\)

显然不能枚举每个集合,我们从 $\gcd $ 的众多角度思考这个问题。

显然 \(\gcd(a,b)=\gcd(a,b,a+b)\)

所以令 \(S_u\) 为与右侧点 \(u\) 点相邻的左侧点的集合。

如果 \(S_u \cap S_v=\varnothing\),那么答案为 \(\gcd(c_u,c_v)\)

如果 \(S_u=S_v\),那么这个集合的和显然为 \(c_u+c_v\)

如果 \(S_u\cap S_v\neq \varnothing\) 时,结果为 \(\gcd(c_u,c_u+c_v)\)\(\gcd(c_v,c_u+c_v)\)\(\gcd(c_u,c_v,c_u+c_v)\)。其最终的结果均为 \(\gcd(c_u,c_v)\)。(三种情况分别对应两种包含和一种只相交一部分)

所以我们只需要判断两个右侧的点的集合是否相等即可。

这个东西可以哈希,也可以直接使用 map+vector

const int N=500005;
int n,m;ll a[N];
vector<int>lis[N];
map<vector<int>,ll>val;
inline void cfmode(){
	val.clear();
	n=read(),m=read();
	for(int i=1;i<=n;++i){
		a[i]=read();
		lis[i].clear();
	}
	for(int i=1;i<=m;++i){
		int u=read(),v=read();
		lis[v].push_back(u);
	}
	for(int i=1;i<=n;++i){
		sort(lis[i].begin(),lis[i].end());
		if(lis[i].size())val[lis[i]]+=a[i];//size!
	}
	ll ans=0;
	for(auto it:val)ans=__gcd(ans,it.second);
	printf("%lld\n",ans);
}
int main(){
	int T=read();
	while(T--)cfmode();
	return 0;
}

本文作者:BigSmall_En

本文链接:https://www.cnblogs.com/BigSmall-En/p/16656264.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   BigSmall_En  阅读(58)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起