https://codeforces.com/problemset/problem/1322/C
参考博客:https://blog.csdn.net/jk_chen_acmer/article/details/107296232
GCD(a+b+c,b+c+d,a+b+c+d)
辗转相减后得到:GCD(a,b+c,d)
分析就可以得到结论:对于右边的点,若两个点(这里的b和c)连接的点集相同(AB),则这两个点为一类点。
结果答案为所有类点内部权值和的gcd。
而分析哪些点为一类用哈希即可。
启发:碰到和有关的gcd尝试用辗转相减法。
当然cf的话肯定要双模数咯。还有数据量输入大的时候要scanf..这次cf把cin卡了(我关了同步流的
写哈希的话可以直接map里面套个vector<>,即map<vector<int>, int>
将向量映射到一个整数。
#include<iostream>
#include<vector>
#include<queue>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<cstdio>
#include<algorithm>
#define debug(a) cout<<#a<<"="<<a<<endl;
using namespace std;
const int maxn=5e5+100;
typedef long long LL;
typedef pair<LL,LL> p;
LL c[maxn],g[maxn];
const int P=131;
const int mod1=19260817;
const int mod2=19660813;
vector<int>v[maxn];
int main(void)
{
//cin.tie(0);std::ios::sync_with_stdio(false);
int t;scanf("%d",&t);
while(t--)
{
// pair<LL,LL>p;
map<p,LL>map1;
int n,m;scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++) scanf("%lld",&c[i]),v[i].clear(),g[i]=0;
for(int i=1;i<=m;i++){
LL x,y;scanf("%d%d",&x,&y);v[y].push_back(x);
}
for(int i=1;i<=n;i++){
if(!v[i].size()) continue;
sort(v[i].begin(),v[i].end());
}
for(int i=1;i<=n;i++){
int hx1=0;int hx2=0;
if(v[i].size()==0) continue;
for(int j=0;j<v[i].size();j++)
{
hx1=(hx1*P%mod1+v[i][j]%mod1)%mod1;
hx2=(hx2*P%mod2+v[i][j]%mod2)%mod2;
}
p k={hx1,hx2};
if(!map1[k]) map1[k]=i;
g[map1[k]]+=c[i];
}
LL gcd=0;
for(int i=1;i<=n;i++) gcd=__gcd(gcd,g[i]);
printf("%lld\n",gcd);
}
return 0;
}