数论及其应用——同余问题

 

  写在前面:《在数论及其应用——素数问题》一文中,笔者只是简单的介绍了一下拓展欧几里得算法可以解决同余问题,但没有详细的展开论述。这篇文章,就是针对数论中的同余问题,展开较为详细的探讨。

  我们通过一个简单的题目,来进入关于同余问题的学习。(Problem source : pku 2769)

  数论及其应用——同余问题_第1张图片

    题目大意:给出n个数,你需要找出一个最小的m,使得这n个数中对m取模有n个不同的结果(任意两个数对m取模的结果不等)。
  这道题不论从数理分析还是编程实现,都很基础,我们只是通过这个问题来初步了解一下什么是同余问题。
  数理分析:这其实就是最基本的同余问题——a = b (mod m)。但是题目要求任意的两个数字不可同余,那么我们只需要排除掉所有同余情况即可。
   编程实现:我们只需设置两层循环,对m由小到大进行穷举即可。穷举过程中,我们需要开设一个记录余数的布尔数组p,当穷举时算出余数为i,如果p[i] = 1,表明之前出现过此余数,那么就跳出循环寻找新的m。
   参考代码如下。

 

#include<cstdlib>
#include<iostream> #include<string.h> using namespace std; bool p[100001]; int d[1000001]; int main() { int ncases; int num , i , j , k; cin >> ncases; while(ncases--) { cin >> num; for(i = 0;i < num;i++) cin >> d[i]; bool find; for(i = 1;;i++) { memset(p , 0 , sizeof(p)); find = 1; for(j = 0;j < num;j++) { if(p[d[j]%i]) { find = 0; break; } p[d[j]%i] = 1; } if(find) break; } cout << i << endl; } return 0; }

 

  我们再来看一道简单的同余问题。(Problem source : hdu 1021)

  数论及其应用——同余问题_第2张图片

  这道题目在数理分析上没有什么难度,困难点就是n的数据的大小。随着n的增大,我们得到的这个数列的值会变大,由于其递推式是前两项的加和,我们可以考虑只记录这个数列每一项余3的结果,由于是加法,结果不会发生改变。
  这样我们容易得到下面的代码。

#include<stdio.h>
using namespace std;
const int maxn = 1000;
int main()
{
     int F[maxn];
     int i , n;
     F[0] = 7%3, F[1] = 11%3;

     for(i = 2;i < maxn;i++)
     {
          F[i] = (F[i-1] + F[i-2])%3;
     }
     while(scanf("%d",&n) != EOF)
     {
          if(F[n] == 0)   printf("yes\n");
          else            printf("no\n");
     }

}

  但是我们可以看到,这里n的最大值可以取到1000000,如果规定这个数为数组长度,会溢出的。所以我们还需要进行优化。此时我们想到在解决素数问题的时候,面对大数据,我们往往避开直接运算而采用寻找分布规律的方法。这里同样也是适用的,我们通过简单的打表会发现,n = 2,6,10,14,18……的时候会输出yes,也就是说,n%4 = 2时,输出yes。
  这样就不会出现空间溢出的情况了,参考代码如下。
 

#include<stdio.h>
using namespace std;

int main()
{
   int n;
     while(scanf("%d",&n) != EOF)
     {
          if(n%4 == 2)   printf("yes\n");
          else            printf("no\n");
     }

}

 


 
 

你可能感兴趣的:(数论及其应用——同余问题)