Instant Noodles(辗转相减法+哈希)

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;
}

猜你喜欢

转载自blog.csdn.net/zstuyyyyccccbbbb/article/details/108890752