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 中国大陆许可协议进行许可。
分类:
,
标签:
,
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步