<8/2>集训日记

今天看了有关欧拉函数,抽屉原理的内容。

首先欧拉函数phi(m)表示的是[1,m-1]中与m互质的数的个数,利用容斥原理可以给出其计算公式:

phi(m)=m*(1-1/p1)*(1-1/p2)**(1-1/pk) 其中p1,p2,,pkm的全部素因子。

以下是求数m的欧拉函数的代码:

代码1:此过程可求所有数的欧拉函数,适用于涉及多个数的欧拉函数的题

#include <cstdio>

#include <cstring>

#define LL long long

#define MAX 32768+1

using namespace std;

int eu[MAX];

void euler()//求出所有数的欧拉函数

{

        inti, j;

        for(i= 2; i < MAX; i++)

        {

                 if(!eu[i])//用此判断i是不是素数 只需要将素数带入下一步

                 {

                         for(j= i; j < MAX; j += i)//所有素因子中包含i

                         {

                                  if(!eu[j])eu[j] = j;//如果在j之前没出现素因子,先乘它自己

                                  eu[j]= eu[j]/i*(i-1);//相当于找到素因子 然后乘以原公式中的(1-1/pi)

                         }

                 }

        }

}

int main()

{

        intt, n;

        euler();

        scanf("%d",&t);

        while(t--)

        {

                 scanf("%d",&n);

                 printf("%d\n",eu[n]);

        }

        return0;

}

这个方法相当于在素数i++的过程中,对多个数同时进行欧拉函数的计算,举例来说:

i=2时,利用j=j+i这个循环,将所有能被2整除的数,也就是有2这个素因子的数进行了第一步计算(1-1/pi)

i=3时,将有3这个素因子的数进行了乘(1-1/pi)的计算,其中,像eu[6]这个数,就带着之前在i=2时计算后的结果进行了第二次乘(1-1/pi)的计算;

i=4时,以下的过程是没有意义的,因为i=2时已经计算完毕了,所以所有的合数i都不需要进行下去,于是用if(!eu[i])判断i是不是素数,只需要将素数带入下一步。

 

代码2:这个过程只求了输入的数n的欧拉函数

#include <iostream>

#include <algorithm>

#include <cmath>

using namespace std;

typedef long long ll;

ll Euler(ll n)

{

        llm=sqrt(n+0.5);

        llans=n;//欧拉函数第一步:乘本身

        for(inti=2;i<=m;i++)

        {

                 if(n%i==0)//找到n的素因子i

                 {

                         ans=ans/i*(i-1);//(1-1/i)

                 }

                 while(n%i==0)//不再考虑素因子i

                 n/=i;//n中的i全除掉

        }

        if(n>1)//素因子大于m或者n就是素数

        ans=ans/n*(n-1);

        returnans;

}

int main()

{

        lln;

        while(cin>>n&&n)

        {

                 llans=Euler(n);

                 cout<<ans<<endl;

        }

        return0;

}

这个方法就是最基本的计算,找到n的不重复素因子,按照公式n*(1-1/p1)*(1-1/p2)**(1-1/pk)计算。

 

单纯计算欧拉函数的题都比较容易,另外还有一种题型是结合欧拉函数和容斥原理的,如[HDOJ1695]

题意:给两个区间[a,b][c,d],求出有多少个数对(x,y)满足gcdx,y== kgcd为最大公约数。其中x属于区间[a,b] y属于区间[c,d],且 (x,y)  (y,x)算一个数对。(题目说明a,c均可假设为1

 

对题目进行分析,可以利用n = b / k m = d / k转化区间,将问题变为求区间[1,n] [1, m] 里面所有不重复的质数对(xy),质数对的求解就可以利用欧拉函数和容斥原理了。

首先,可以假设n <= m

x,y同时x属于区间[1,n]时,所有不重复质数对(x,y)的数目就为n个数的欧拉函数之和;

x属于区间[1,n] y属于区间[n+1,m]时,可以利用容斥原理枚举y,求区间[1,n]里面与该y互质的个数,最后累加。

 

所以在这个题中就需要用上面写到的求多个数的欧拉函数的代码,即代码1,然后将1n所有的欧拉函数值求和,就是[1,n]中不重复的质数对。容斥原理部分不须变通。

这题还需要注意的一个小地方就是假设了n<=m,所以需要在一开始调整n,m顺序。

所用到的小代码之前都涉及了,不再粘过来了。

 


接下来是抽屉原理相关内容。

首先,抽屉原理在数学领域的定义是:将m个球放到n只抽屉中,一定有一只抽屉放进的球数不少于[(m-1)/n]+1个,其中[a]表示不大于a的最大整数,即向下取整。

但一般情况,普遍应用的定义是:将n+1个球放入n个抽屉,则有个抽屉中至少有2个球。

 

这里详细写一道抽屉原理的典型应用题:一个由n个数组成的数列,一定能找出若干个连续的数使它们之和能被n整除。[POJ 2356 Find AMultiple]

题目大意是:先给出一个数N,接着再给出N个数,要你从这N个数中选择若干个连续的数,使得其和是N的倍数。输出的第一行是选择元素的个数M,接着M行分别是选择的元素的值。答案若有多个输出任意一个即可。如果找不到这样的答案则输出0

解题思路如下:

n个数记为a[1],a[2],...a[n].设置一个数组sumsum[i] = a[1] + a[2] + ...a[i] 

1、如果存在一个k使得sum[k]%n==0,那么输出前k个数即可;

2、如果对于任意的k都有sum[k] % n != 0,那么nsum数组的元素除n后将会得到n个余数,这些余数一定大于等于1且小于等于n-1,由抽屉原理,这n个余数中一定可以找到两个相等的余数,即存在i,j,使得sum[i]%n=sum[j]%n(不妨设j>i),那么,(sum[j]-sum[i]%N=0,故sum[j]-sum[i]N的倍数。此时,输出i + 1j之间的数即可。

 

POJAC的代码如下:

#include<iostream>

#include<cstdio>

using namespace std;

int sum[10005],a[10005];

int main()

{

        intn;

        intp=0;//标记

        scanf("%d",&n);

        for(inti=1;i<=n;i++)

        {

                 scanf("%d",&a[i]);

                 sum[i]=sum[i-1]+a[i];

                 if(sum[i]%n==0)p=i;//直接找到

        }

        if(count!=0)//直接找到的情况输出a[1]a[i]

        {

                 printf("%d\n",p);

                 for(inti=1;i<=p;i++)

                 {

                         printf("%d\n",a[i]);

                 }

                 return0;

        }

        for(inti=1;i<=n;i++)

        {

     for(int j=i+1;j<=n;j++)

     {

       if((sum[j]-sum[i])%n==0)

       {

           printf("%d\n",j-i);//j-i即为要输出的元素的个数

           for(int k=i+1;k<=j;k++)//输出a[i+1]a[j]

           printf("%d\n",a[k]);

       }

     }

    }

}

看完了一个博客中有关容斥原理欧拉函数和抽屉原理的内容,感觉计算顺序、循环都与纯数学的方式有所差别,并且有些题中还需要考虑复杂度,可能会出现超时的情况。

 以上~

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值