首页 > 其他 > 详细

P2158仪仗队

时间:2019-07-03 09:19:45      阅读:155      评论:0      收藏:0      [点我收藏+]

今天早上你谷崩了

由于脑子抽筋,所以选了一道数学题来做。做着做着就疯了

传送

技术分享图片

技术分享图片

窝盟先画张图冷静冷静

技术分享图片

 

这是样例的图,其中蓝点是有学生的地方。

窝盟来看一下那些学生可以被C君看到。

假设这张图是一个坐标系,C君在(0,0)。

C君可以看到的学生:(1,0),(0,1),(1,1),(1,2),(2,1),(1,3),(3,1),(2,3),(3,2)

我们画下来(下图中红点是可以看到的学生)

技术分享图片

我们发现红点的横纵坐标的最大公约数都是1,且所有红点关于y=x对称。

所以我们可以求出来一半的红点,再*2-1(因为(1,1)关于y=x对称后还是(1,1),所以要-1)

我们再看一下数据范围:技术分享图片

显然O(n2)枚举横纵坐标会TLE。

我们发现对于合法的点(i,j)来说,gcd(i,j)=1,也就是说i与j互质。所以我们要找出所有符合(i,j)互质的二元组(i,j)。

仔细思考,想起有一个神奇的函数,叫欧拉函数。φ(n)是求从1到n-1中,有多少个与n互质的数。

为了不重复,不少求符合条件的(i,j),我们求出1到n-1这些数的φ,然后乘2.

似乎少求了什么东西。是什么呢?是什么呢?是什么呢?

我们好像忽略了(1,0)和(0,1)这两个点,还把(1,1)算了两遍

那就在当前答案上直接+1好了

怎么快速求φ?

我们先看几个式子:

若n,m互质,φ(nm)=φ(n)φ(m)

p为质数,φ(p)=p-1;

通向公式:φ(n)=n(1-1/p1)(1-1/p2).....(1-1/pk)  (其中p1,p2...pk为n的所有质因子)

技术分享图片

所以φ(n)=n/pi*(pi-1) (1<=i<=k)

以下是求φ的代码:

int phi(int k)
{
    if(k==1)return 1;
    if(!no[k])return k-1;
    cn=0;
    int p=k,h=k;
    for(int i=2;i*i<=k;i++)
    {
        if(h%i==0)
         {
             p=p/i*(i-1);//上面的推导 
             h/=i;
             while(h%i==0)
              h/=i;//我们只用到不同的质因数
         }
        
    }
    if(h>1) p=p/h*(h-1);//如果此时的h是最后一个质因数,还要更新p
    return p;
}

 

本题代码(由于洛谷崩了所以我也不知道能不能ac,但目测可以)

#include<iostream>
#include<cstdio>
#include<queue>
#include<cstring>
#define ll long long
using namespace std;
int n,pre[40009],cnt,all,cn,ys[40009];
bool no[40009];
int read()
{
    char ch=getchar();
    int x=0;bool f;
    while(ch<0||ch>9)
    {
        if(ch==-)f=1;
        ch=getchar();
    }
    while(ch>=0&&ch<=9)
    {
        x=(x<<3)+(x<<1)+(ch^48);
        ch=getchar();
    }
    return f?-x:x;
}
int phi(int k)
{
    if(k==1)return 1;
    if(!no[k])return k-1;
    cn=0;
    int p=k,h=k;
    for(int i=2;i*i<=k;i++)
    {
        if(h%i==0)
         {
             p=p/i*(i-1);φ(m)=m-1 
             h/=i;
             while(h%i==0)
              h/=i;
         }
        
    }
    if(h>1) p=p/h*(h-1);
    return p;
}
int main()
{
   n=read();
   all=0;
   for(int i=2;i<=n;i++)//线性筛判断质数
    {    
        if(!no[i])
            pre[++cnt]=i;
        for(int j=1;j<=cnt;j++)
        {  
            if(i*pre[j]>n)break;
            no[i*pre[j]]=1;
            if(i%pre[j]==0)
            break;    
        }
    }
    no[1]=1;
    for(int i=1;i<=n-1;i++)
    {
         all+=phi(i);
    }
   all*=2;
   all+=1;
   printf("%d",all);  
}

 

P2158仪仗队

原文:https://www.cnblogs.com/lcez56jsy/p/11124260.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!