首页 > 其他分享 >CodeForces - 1986G1 & CodeForces - 1986G2

CodeForces - 1986G1 & CodeForces - 1986G2

时间:2024-07-11 10:57:23浏览次数:10  
标签:cnt gcd 复杂度 个数 CodeForces 1986G2 1986G1 统计

经过基本观察,可得当点对 \((i,j)\) 合法时,有 \(a_i|b_j,a_j|b_i\),其中 \(a_i=i/gcd(p_i,i),b_i=p_i/gcd(p_i,i)\),证明显然。
如何维护?考虑开 \(mp_{x,y}\) 表示 \(x=a_i\),\(y|b_i\) 的个数。对于点 \(i\) 点对个数即为 \(\sum\limits_{d|b_i} mp_{d,a_i}\)
时间复杂度为 \(O(nlog^2n)\),空间复杂度为 \(O(nlogn)\),可通过 \(G1\)。
如何优化?考虑枚举 \(x\),那么只需一个 \(O(n)\) 的数组维护。令 \(cnt_{(x),y}\) 为 \(a_i=x,y|b_i\) 的点对数,统计答案时枚举 \(x\) 的倍数 \(y\),
贡献点对个数为 \(\sum\limits_{b_i=y}cnt_{(x),a_i}\),统计完 \(x\) 后要清空数组。

这样统计会统计到 $(i,j),i\ge j $ 的点对,当 \(a_i|b_i\) 时会被统计,需减掉,根据对称性将最终答案数以 2 即可。

因为每个点只会在 \(p_i\) 的因子处贡献,且 \(\{p_i\}\) 为排列,所以时间复杂度为 \(O(nlogn)\)

//G1
void Main(){
	n=rd,ans=0;
	for(int i=1;i<=n;i++)
		p[i]=rd;
	for(int i=1;i<=n;i++){
		int g=__gcd(p[i],i);
		a[i]=i/g,b[i]=p[i]/g;
		// a[i]|b[j],a[j]|b[i]
		//统计 ans
		for(int j:fac[b[i]])
			ans+=mp[j][a[i]];
		for(int j:fac[b[i]])
			mp[a[i]][j]++;
	}
	for(int i=1;i<=n;i++)
		for(int j:fac[b[i]])
			mp[a[i]][j]--;
	cout<<ans<<endl;
}

signed main(){
	for(int i=1;i<=N-10;i++)
		for(int j=i;j<=N-10;j+=i)
			fac[j].pb(i);
	int T=rd;
	while(T--) Main();
}
//G2
void Main(){
	n=rd,ans=res=0;
	for(int i=1;i<=n;i++)
		p[i]=rd;
	for(int i=1;i<=n;i++){
		int g=__gcd(p[i],i);
		a[i]=i/g,b[i]=p[i]/g;
		if(b[i]%a[i]==0) res++;
		vec1[a[i]].pb(b[i]);
		vec2[b[i]].pb(a[i]);
	}
	for(int x=1;x<=n;x++){
		for(int y:vec1[x]) for(int z:fac[y]) cnt[z]++;
		for(int y=x;y<=n;y+=x) for(int z:vec2[y]) ans+=cnt[z];
		for(int y:vec1[x]) for(int z:fac[y]) cnt[z]--;
	}
	printf("%lld\n",(ans-res)/2);
	for(int i=1;i<=n;i++) vec1[i].clear(),vec2[i].clear();
}

标签:cnt,gcd,复杂度,个数,CodeForces,1986G2,1986G1,统计
From: https://www.cnblogs.com/smilemask/p/18295621

相关文章

  • CodeForces - 1984E
    题目大意每次在每个联通块中选一个点\(u\),删除这个点使得联通块分成若干个联通块,再从联通块中选点\(v\),在新树上连接\(u,v\),求新树叶节点的最大个数。分析易转化为求原树的最大独立集,设\(f_{u,0/1}\)为以1为根时不选/选\(u\)的最大独立集。显然有:\[dp_{u,0}=\sum\li......
  • 高考后第一次Codeforces Round 952 (Div. 4)
    ACreatingWords思路:拿一个容器交换两数值即可#include<bits/stdc++.h>usingnamespacestd;constintN=100001;chara[N],b[N];intmain(){intn;scanf("%d",&n);while(n--){scanf("%s%s",a,b);charjia......
  • Codeforces Round 954(Div. 3)
    CodeforcesRound954(Div.3)目录CodeforcesRound954(Div.3)\(C\).UpdateQueries\(D\).MathematicalProblem\(E\).BeautifulArray方法一:贪心+滑动窗口方法二:DP\(C\).UpdateQueries对索引数组\(ind\)去重排序对字符串\(c\)排序顺序遍历索引数组,将\(s[ind[i]......
  • Codeforces Round 916 (Div. 3)
    A.ProblemsolvingLog签到题,对于给出的字符串,记录每个字母出现的次数,然后遍历一遍,如果对应的字母出现的次数大于它的位次,则说明该题被解出来了,最后输出解题数量即可点击查看代码#include<iostream>#include<cstdio>#include<algorithm>#include<cmath>#include<vector>#......
  • Codeforces Round 956 (Div. 2) 部分题解A~C
    A.ArrayDivisibility题目大意构造长度为n的数组,满足:所有j的aj之和可以被k整除,其中j是k的倍数,k的取值为1~n。思路构造序列1->n即可满足条件。代码实现voidsolve(){  lln;cin>>n;  for(inti=1;i<=n;i++)cout<<i<<"";  cout<<"\n"......
  • Codeforces Round #956 (Div. 2) and ByteRace 2024
    Preface连着好几天因为熬夜看LOL比赛导致白天精神萎靡,都没精力VP了而且明天就要开始统一训练了,趁着最后一天补一下前两天因为看比赛没打的这场吧这场只能说是战术正确,想了会E没啥思路就马上转头去把F写了,后面回头慢慢想E也想出来了,最后极限2h14min出了EA.ArrayDivisibility......
  • codeforces 955 div 2 D
    题目链接D.Beautyofthemountains题目大意解题思路首先记录所有雪山和没有雪山两种山峰的高度差为\(tot\),然后对于每个可能的子矩,我们可以每次给所有山峰都加一或者减一,因此只要计算出矩阵内两种山峰的个数差的绝对值我们就能得到每次操作该子矩阵对tot的贡献\(z_{i}......
  • Codeforces Round956(div2) A~C
    A.ArrayDivisibility题意:对于所有k=1~n,能被j=1~n整除,要求以这些j作为下标a[j]的和也能够被k整除思路:题目有点绕,但是仔细读懂题目其实会发现,其实就是从1到n按顺序输出一遍...,别被样例忽悠了voidsolve(){ intn; cin>>n; for(inti=1;i<=n;i++){ cout......
  • Codeforces Round 953(Div.2) 题解(A-E)
    CodeforcesRound953(Div.2)题解(A-E)A题意Alice有n本书,第一本书有\(a_1\)页,序号为1,第二本书有\(a_2\)页,序号为2,……,第n本书有\(a_n\)页,序号为n。Alice将把所有书分成两堆,并阅读每一堆中序号最大的一本书。Alice喜欢读书,请你告诉她,她最多可以读多少页的书。Solution第......
  • CodeForces CF1980C Sofia and the Lost Operations 题解 但是最后TLE 仅供思路参考
    CodeForcesCF1980CSofiaandtheLostOperations题解嗨嗨,又来了啊,蒟蒻再来一篇题解SofiaandtheLostOperations题面翻译索菲亚有一个包含$n$个整数的数组$a[1],a[2],…,a[n]$。有一天她对这个数组感到厌倦,于是决定顺序地对其应用$m$个修改操作。每个修改操作由一......