UVA 11426 (欧拉函数&&递推)

时间:2023-03-09 20:20:49
UVA 11426 (欧拉函数&&递推)

题意:给你一个数N,求N以内和N的最大公约数的和

解题思路:

一开始直接想暴力做,4000000的数据量肯定超时。之后学习了一些新的操作。

题目中所要我们求的是N内gcd之和,设s[n]=s[n-1]+gcd(1,n)+gcd(2,n)+gcd(3,n)+gcd(4,n).......

再设f[n]=gcd(1,n)+gcd(2,n)+gcd(3,n)+gcd(4,n).......;

思考一下,假设gcd(x,n)=ans,ans便是x和n的最大公约数,那么有几个ans我们将某ans的个数sum(num*ans)是不是就是当前f[n]的值;

那么某个ans的个数num我们该怎么求???

gcd(x,n)=ans;那么gcd(x/ans,n/ans)就是1;就是说x/ans和n/ans是互素的,那么求n以内和n互素的数的个数我们怎么办???就用欧拉函数phi;

其个数就是phi[n/ans];

然后,,,,你以为求这点就做完了是吗??玩笑,,,;

你可以直接打出4000 000欧拉表,那么我们该怎么遍历赋值f[n];f[n]=num*ans;我们遍历n在遍历ans么??这个不现实,在当前这个n中会有部分ans白白计算

所以我们最好的办法就是先行枚举ans,我们知道,当前ans所对应的n一定是ans的倍数,所以我们遍历n极为方便,只需要令n=2*ans,3*ans,4*ans,5*ans......

这里有个点就是n不能是ans,所以我们第二重循环里就应该从2*ans开始;这个地方一会在代码中点出;

具体就是这么多;

AC代码

 #include<stack>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm> using namespace std; #define INF 0x3f3f3f3f
typedef long long ll;
const ll maxn = ;
ll n; ll euler[maxn];
ll fun_[maxn]; void euler_(ll maxn)
{
for (int i=;i<=maxn;i++)
{
euler[i]=i;
}
for (int i=;i<maxn;i++)
{
if (euler[i]==i)
{
for (int j=i;j<maxn;j+=i)
{
euler[j]=euler[j]/i*(i-);
// cout<<euler[j]<<endl;
}
}
}
} ll s[maxn]; int main()
{
euler_(maxn);
//memset(fun_,0,sizeof(fun_));
for (int i=;i<=maxn;i++)
{
for (int j=i+i;j<=maxn;j+=i)
{
//cout<<i<<" "<<n/i<<" "<<euler[n/i]<<endl; fun_[j]+=i*euler[j/i];
//cout<<fun_[j]<<endl;
}
}
s[]=; for (int i=;i<=maxn;i++)
{
s[i]=s[i-]+fun_[i];
//cout<<i<<" "<<s[i]<<endl;
}//cout<<"***********"<<endl;
while (cin>>n&&n)
{
//cout<<n<<endl;
cout<<s[n]<<endl;
}
}