洛谷UVA10820

由 5+1 发布

先来看一下题意

本题的本质是,输入 $n$ ,有多少个二元组$(x,y)$满足$gcd(x,y)=1$

而我们不难想到

对于某个 $x$ ,小于 $x$ 的与它互质的数的个数就是$phi(x)$,因为$x$和$y$交换算两次,所以是$2×phi(x)$。

对于$(1,1)$是不能交换的。

所以就是

所以输入 $n$ ,答案就是$1+2*\sum{_{i=2}^n phi(i)}$,输出即可。

先看一下求 $Euler$

我们可以用一个$euler$函数也就是$euler$线性筛法:$EulerTable()$,$phi[x]$用来计算 $x$ 的个数的euler值(如果不会$euler$的小伙伴,你应该先自学一下$euler$)。

ll phi[1900900],prime[1900900],tot;

void EulerTable(ll n)
{
  phi[1]=1;
  for(ll i=2;i<=n;i++)
  {
    if(phi[i]==0)
    {
      phi[i]=i-1,prime[tot++]=i;
    }
    for(ll j=0;j<tot && i*prime[j]<=n;j++)
    {
      if(i%prime[j]==0)
      {
        phi[i*prime[j]]=phi[i]*prime[j];
        break;
      }
      else
      {
        phi[i*prime[j]]=phi[i]* (prime[j]-1);
      }
    }
  }
}

最后

我们看看主函数。

先计算一下到 50011 的所有数的Euler值,调一遍EulerTable函数即可。

然后跟据上面的思路可以写出

int main(){
  EulerTable(50011);
  ll n;
  scanf("%lld",&n);
  while(n!=0)
  {
    ll ans=0;
    for(int i=2;i<=n;i++)
    {
      ans+=phi[i];
    }
    printf("%lld\n",ans<<1|1);
    scanf("%lld",&n);
  }
}

最后附上完整代码

$\color{red}Code:$

#include<iostream>
#include<cstdio>
using namespace std;
typedef long long ll;
const ll MAXN=50011;
ll phi[1900900],prime[1900900],tot;

void EulerTable(ll n)
{
  phi[1]=1;
  for(ll i=2;i<=n;i++)
  {
    if(phi[i]==0)
    {
      phi[i]=i-1,prime[tot++]=i;
    }
    for(ll j=0;j<tot && i*prime[j]<=n;j++)
    {
      if(i%prime[j]==0)
      {
        phi[i*prime[j]]=phi[i]*prime[j];
        break;
      }
      else
      {
        phi[i*prime[j]]=phi[i]* (prime[j]-1);
      }
    }
  }
}


int main(){
  EulerTable(50011);
  ll n;
  scanf("%lld",&n);
  while(n!=0)
  {
    ll ans=0;
    for(int i=2;i<=n;i++)
    {
      ans+=phi[i];
    }
    printf("%lld\n",ans<<1|1);
    scanf("%lld",&n);
  }
}

暂无评论

发表评论