CF1322C Instant Noodles

Solution

前置知识

因为 \(\gcd(a,b)|a,\gcd(a,b)|b,\gcd(a,b)|a+b\) ,而且 \(\gcd(a,b,a+b)\leq \min(a,b,a+b)\leq a,b\leq a+b\) ,可以得到 \(\gcd(a,b)=\gcd(a,b,a+b)\)

题解

我们设 \(i,j\) 为右边两个点, \(S_i,S_j\) 为两个点所连接的左边的点的集合

\(S_i∩S_j=\varnothing\) 时,直接求 \(\gcd(c_i,c_j)\) 即可

\(S_i=S_j\) 时,因为一样,所以可以将 \(c_i\)\(c_j\) 合并起来

\(S_i∩S_j\not=\varnothing\) 时,求的肯定是 \(\gcd(c_i,c_i+c_j)\)\(\gcd(c_j,c_i+c_j)\)\(\gcd(c_i,c_j,c_i+c_j)\) 结果都是 \(\gcd(c_i,c_j)\)

其实和别的题解差不多\o/,但是咱没用 \(hash\)因为不会。(而且是完整的代码 ԅ(¯﹃¯ԅ)

代码

#include<bits/stdc++.h>
#define ll long long

using namespace std;
const int N=5e5+10;
int T,n,m;
ll c[N];
set<int> g[N];//我这里是拿set求的集合
map<set<int>,ll> mp;//拿map做的映射

ll gcd(ll x,ll y){
    return y==0?x:gcd(y,x%y);
}

int main(){
    scanf("%d",&T);
    while(T--){
        mp.clear();
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)
            scanf("%lld",&c[i]);
        for(int i=1;i<=n;i++) g[i].clear();
        while(m--){
            int u,v;
            scanf("%d%d",&u,&v);
            g[v].insert(u);
        }
        for(int i=1;i<=n;i++)
            if(!g[i].empty()) mp[g[i]]+=c[i];
        ll ans=0;
        for(auto &i:mp)
            if(ans) ans=gcd(ans,i.second);
            else ans=i.second;
        printf("%lld\n",ans);
    }
    return 0;
}
posted @ 2020-09-26 09:16  jasony_sam  阅读(163)  评论(0编辑  收藏  举报