题面
题目描述
今天藤藤闲来无事,想到了一个奇怪的问题,但这个问题把它自己难住了,需要你来帮帮他。
一个长度为 n 的序列,从这序列里面选4个数,要求这四个数的 gcd 为1,不要求它们两两互质。
定义:gcd 即为数学意义上的最大公约数
假设四个数为a,b,c,d 那么四个数的最大公约数被定义为gcd(a,gcd(b,gcd(c,d))),
此处函数 gcd 为求两个数的最大公约数
你需要帮助藤藤找到这个序列里一共有多少个满足条件的四元组
输入格式
第一行为整数n,序列元素的个数。
第二行有n个数ai,表示序列里面的元素(存在多个元素相等)
输出格式
输出满足条件的四元组数量
输入输出样例
输入 #1复制
4 2 3 4 5
输出 #1复制
1
输入 #2复制
4 2 4 6 8
输出 #2复制
0
输入 #3复制
7 2 3 4 5 7 6 8
输出 #3复制
34
说明/提示
样例解释:
样例1:2345一个满足条件的四元组
样例2:没有满足条件的四元组
样例3:除了2468,其余都满足
对于10%的数据,满足1≤n≤10,1≤ai≤100
对于30%的数据,满足1≤n≤50,1≤ai≤10000
对于100% 的数据,满足1≤n≤10000,1≤ai≤10000
解答
30分解法
既然说是四个数的 gcd 为 1,不妨开四重 for 循环解答。
注意每重都要从上一重加 1 开始循环,最后判断就行。
时间复杂度 O(n^4) 。对于 n 小于 50 是不会 TLE 的。
判断 gcd 可以写函数
int gcd(int n,int m){
if(m==0)return n;
return gcd(m,n%m);
}
当然,万能头里也有自带函数 __gcd,很方便。
代码
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll N=1e4+5;
ll n,a[N],ans;
int main(){
cin>>n;
for(int i=1;i<=n;i++)cin>>a[i];
for(int i=1;i<n-2;i++)
for(int j=i+1;j<n-1;j++)
for(int k=j+1;k<n;k++)
for(int l=k+1;l<=n;l++)
if(__gcd(a[i],__gcd(a[j],__gcd(a[k],a[l])))==1)
ans++;
cout<<ans;
return 0;
}
很好,30分。
满分做法
我们知道如果两数的最大公约数为 1,说明它们俩的所有因数只有 1 相同。对,先分解每个数的因数!我们用 dp 数组记录所有有 i 因数的数的个数。……额,可能有些绕口,那就在代码中理解。
void init(ll x){
for(ll i=1;i*i<=x;i++){
if(x%i==0){
dp[i]++;
if(x/i!=i)dp[x/i]++;
maxn=max(maxn,x/i);
}
}
}
maxn 用来记录因数的最大值,以便后面循环。当然,x / i 是大于等于 i 的。
当前时间复杂度 O(√ ̄n),加上循环 a [ i ] 时间复杂度 O(n√ ̄n);
接着就要开始加工了,首先要去掉那些不满四个的因数,还原回 0。其他的加工成 C ( i , 4 ),表示共有多少种不同的组合法,可以简单写成
dp[i]=dp[i]*(dp[i]-1)*(dp[i]-2)*(dp[i]-3)/24;
C表示组合数,没学过的可以百度搜一下。
然后,我们要除去一些重复的因数,比如因数 3 的数量包含了因数 6 的数量,所以要减去因数 6 的数量,可以每次让 i 乘 2 去找因数 i 的倍数,如果有且没越界,就减去。
注意循环要从 maxn 开始反着循环到 1,这样减去时就不会重复;
最后输出因数为 1 的数量,也就是 dp[1] 就行了。
AC主函数代码
(预处理前面已经公布)
int main(){
// freopen("quaternion.in","r",stdin);
// freopen("quaternion.out","w",stdout);
cin>>n;
for(int i=1;i<=n;i++){
cin>>a[i];
init(a[i]);
}
for(int i=1;i<=maxn;i++)
if(dp[i]>=4)
dp[i]=dp[i]*(dp[i]-1)*(dp[i]-2)*(dp[i]-3)/24;
else dp[i]=0;
for(int i=maxn;i>=1;i--){
if(dp[i]){
int j=i+i;
while(j<=maxn){
dp[i]-=dp[j];
j+=i;
}
}
}
cout<<dp[1];
return 0;
}
我查了一下,这道我们团队比赛的题目在洛谷上有 原题,竟是 紫题!不过,我把这个代码稍微改一下(变成多组数据),还是AC,并不难。
又来一次完美撒花!
认为讲得好记得关注我 wangkeliniii 谢谢!