• 素数幻方


    素数幻方

     

    Problem Description

    素数幻方全是由素数构成的各行、各列与两对角线之和均相等的方阵。
    试在指定区间[c,d]找出9个素数,构成一个3阶素数幻方,使得该方阵中3行、3列与两对角线上的3个数之和均相等。
    输入区间c,d,输出基于该区间素数构建的所有3阶素数幻方的个数。

    Input

    每行2个整数,表示c和d。

    Output

    每行1个整数,表示[c,d]之间所有3阶素数幻方的个数。

    Sample Input

    1 120

    Sample Output

    2

    解释:

    这是一个好玩的题,说实话,很好玩。我 参考 https://blog.csdn.net/u013514928/article/details/44903743?utm_source=blogxgwz5,之后自己优化了一下时间。很感谢这位大佬,我原本的想法是,从4个数中去循环查找的,结果发现,自己的数学模型存在一个巨大问题,无法保证答案的唯一性,对此,我是很懵的,很谢谢这个大佬的这篇博客,受益匪浅。

    首先,我大致介绍一下我自己对于大佬的博客的理解。

    我们需要3*3阶的素数,也就是需要9 + 1个未知数。按照大佬的数学模型。

    n-x    n+w    n-y

    n+z     n      n-z

    n+y   n-w   n+x

    其中3*n = S, x > y > 0;

    对于这个模型,我们假设n, x, y 是已知的,那么

    w = x + y

    z = x - y

    所以,在x, y, z, w 中 w是最大的,并且,当x = 2 *y的时候。z == y,所以, x == 2*y 这里要注意一下。不能出现。

    在大佬的博客里面,有一个范围的思考计算,这里我们是用不上的,但是,可以考虑去学一下。好吧,很有必要去学一下,学完要记得给大佬点赞。 2 <= y <= n-3     y+2 <= x <= n-3;这个题目已经给定上界,下界了,所以。。。

    最核心的是这个数学模型,想到了这个模型,问题就好解决很多了,剩下的就是优化。

    1、给定的是[c, d]是两个自然数,其中个数为d - c + 1, 但是这两个中间的素数,绝对小于 d - c + 1. 于是乎,打表,一个保存当前数是不是素数的flag_prime, 另一个记录全是素数的number_prime。

    2、我要找到[c, d]中间的素数是那些,我只要知道第一个大于等于C的素数,最后一个小于等于D的素数,可以遍历去找,这里我用的二分,加快时间。得到一个下标区间[tc, td]

    3、大佬从s开始找,也就是说,从[3*d, 3*d]开始遍历,我这里从n开始找,并且n是素数的下标,我就可以保存每一次的更新都是素数,而不再是 +1 +1 + 1了,这样时间再快一点点。

    4、用两个for循环,这个时候,我不再是用y去遍历,而是,直接遍历素数,找到n+y, 然后通过后n+y-n得到y,再判断n-y是不是素数,这样,就不再是+1 +1 +1这样的遍历了,时间再快一点

    具体的看代码:

      1 #include<bits/stdc++.h>
      2 
      3 using namespace std;
      4 const int N = 20000;
      5 
      6 int flag_prime[3*N];
      7 int sums_prime = 0;
      8 int number_prime[N];
      9 
     10 void init(){
     11     flag_prime[0] = flag_prime[1] = 1;
     12     for (int i = 2; i < N; i++){
     13         if (!flag_prime[i]){
     14             number_prime[sums_prime++] = i;
     15             for (int j = 2; j*i < N; j++){
     16                 flag_prime[i*j] = 1;
     17             }
     18         }
     19     }
     20 }
     21 
     22 //3 查找最后一个小于key的元素
     23 int findLastLess( int len, int key)
     24 {
     25     int left = 0;
     26     int right = len - 1;
     27     int mid;
     28 
     29     while (left <= right) {
     30         mid = (left + right) / 2;
     31         if(key > number_prime[mid]) { //当大于的时候,就可以把左边更新一下
     32             left = mid + 1;
     33         }else{
     34             right = mid - 1;
     35         } 
     36     }
     37     return right;
     38 }
     39 
     40 //4 查找第一个大于key的元素
     41 int findFirstGreater(int len, int key)
     42 {
     43     int left = 0;
     44     int right = len - 1;
     45     int mid;
     46 
     47     while (left <= right) {
     48         mid = (left + right) / 2;
     49         if (key < number_prime[mid]) { //  当小于的时候,就可以把右边更新一下
     50             right = mid - 1;
     51         }
     52         else {
     53             left = mid + 1;
     54         }
     55     }
     56     return left;
     57 }
     58 
     59 int func(int n, int c, int d){
     60 
     61    // n = number_prime[n];
     62     int s = number_prime[n];
     63     int  sums = 0;
     64 
     65     for (int i = n+1; i <= d-2; i++){
     66         int y = number_prime[i] - s;
     67         if (flag_prime[s - y]) continue;
     68 
     69         for (int j = i+1; j <= d-1; j++){
     70             int x = number_prime[j] - s;
     71             if(flag_prime[s - x])continue;
     72 
     73             int z = x - y;
     74             int w = x + y;
     75             if(x == 2 * y || s - w < number_prime[c] || s + w > number_prime[d]) continue;
     76            
     77             if (!(flag_prime[s-z] + flag_prime[s+z] + flag_prime[s + w] + flag_prime[s - w] + flag_prime[s + x] + flag_prime[s - x] + flag_prime[s - y] + flag_prime[s + y]) ){
     78                 // printf("%5d %5d %5d
    ", s-x, s+w, s-y);
     79                 // printf("%5d %5d %5d
    ", s+z, s, s-z);
     80                 // printf("%5d %5d %5d
    ", s+y, s-w, s+x);
     81                 // cout << endl;
     82                 sums++;
     83             }
     84         }
     85     }
     86     return sums;
     87 } 
     88 
     89 int main(){
     90     init();
     91     int c, d;
     92     while (cin >> c >> d){
     93         int sums = 0;
     94         int tc = findFirstGreater(sums_prime, c);
     95         int td = findLastLess(sums_prime, d);
     96        // printf("%d %d
    ", tc, td);
     97         for (int s = tc+3; s <= td-3; s++){
     98             sums += func(s, tc, td);
     99         }
    100         printf("%d
    ", sums);
    101     }
    102     return 0;
    103 
    104 }
    View Code

    时间还是很长,但是我想不到,还可以怎么优化了。还是感谢,

     https://blog.csdn.net/u013514928/article/details/44903743?utm_source=blogxgwz5  这个博客,没有这个数学模型,我完全解不出来。

  • 相关阅读:
    day 66
    day 66 作业
    day 65 作业
    day 55 Ajax
    day 56 forms组件
    day 59
    day 58 cookie与session 中间件
    day 54
    day 53
    day 52
  • 原文地址:https://www.cnblogs.com/gznb/p/11207652.html
Copyright © 2020-2023  润新知