Codeforces Round #626 (Div. 2) E. Instant Noodles(二分图,最大公因数)

题意:

给你一个二分图,求左侧端点的所有可能子集中的点相连的右侧端点的权值的和的最大公因数。

题解:

若所有右侧端点均不在同一左侧子集中,则求所有权值的最大公因数即可 。

否则,将在相同左侧子集中的右侧权值合并,求合并权值与其余权值的最大公因数。

证明 :

$gcd(a,a+b)=gcd(a,b),gcd(a,b,c)=gcd(a,gcd(b,c)) 。$

Tips:

Time Limit 2s
ios::sync_with_stdio(false) + cin.tie(nullptr) + cout.tie(nullptr) + & 1965ms
scanf  1622ms
scanf + & 655ms

 

 

 

 

 

简直是降维打击

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;

vector<pair<vector<int>,ll>> v;

bool cmp(pair<vector<int>,ll> & a,pair<vector<int>,ll> & b){//对每个右端点所在的左侧子集排序
    if(a.first.size()!=b.first.size())
        return a.first.size()<b.first.size();
    else
        return a.first<b.first;
}

void solve(){
    int n,m;scanf("%d%d",&n,&m);

    v.clear();
    v.resize(n);

    for(int i=0;i<n;i++)
        scanf("%lld",&v[i].second);
    for(int i=0;i<m;i++){
        int a,b;scanf("%d%d",&a,&b);
        --a,--b;
        v[b].first.push_back(a);
    }

    for(int i=0;i<n;i++)
        sort(v[i].first.begin(),v[i].first.end());
    sort(v.begin(),v.end(),cmp);

    ll ans=0;

    int i=0;
    while(v[i].first.empty()) i++;//跳过空子集
    while(i<n){
        int j=i;
        ll sum=0;
        while(j<n&&(v[i].first==v[j].first)){//合并权值
            sum+=v[j].second;
            ++j;
        }
        ans=__gcd(ans,sum);
        i=j;
    }
    
    printf("%lld\n",ans);
}

int main(){
    int t;scanf("%d",&t);
    while(t--)
        solve();
    return 0;
}

 

posted @ 2020-03-11 18:21  Kanoon  阅读(315)  评论(0编辑  收藏  举报