PAT-2019年秋季考试-甲级 7-1 Forever (20 分| 简单数学,附详细注释,逻辑分析)

写在前面

  • 思路分析
    • Forever number以99结尾
      • Why ?
      • 降低时间复杂度,避免运行超时
    • 详见原因分析
  • 感觉太菜鸡,手高眼低,导致考的太垃圾
    • 有机会再战,记录下今天所思
    • 后续刷题验证

题目详情

  • 7-1 Forever (20)
    “Forever number” is a positive integer A with K digits, satisfying the following constrains:
    
    the sum of all the digits of A is m;
    the sum of all the digits of A+1 is n; and
    the greatest common divisor of m and n is a prime number which is greater than 2.
    Now you are supposed to find these forever numbers.
    
    Input Specification:
    Each input file contains one test case. For each test case, the first line contains a positive integer N (5). Then N lines follow, each gives a pair of K (3<K<10) and m (1<m<90), of which the meanings are given in the problem description.
    
    Output Specification:
    For each pair of K and m, first print in a line Case X, where X is the case index (starts from 1). Then print n and A in the following line. The numbers must be separated by a space. If the solution is not unique, output in the ascending order of n. If still not unique, output in the ascending order of A. If there is no solution, output No Solution.
    

测试用例

  • input:
    2
    6 45
    7 80
    
    output:
    Case 1
    10 189999
    10 279999
    10 369999
    10 459999
    10 549999
    10 639999
    10 729999
    10 819999
    10 909999
    Case 2
    No Solution
    

待验证代码

  • 是否能成功ac,待验证
#include 
#include 
using namespace std;

bool isprime(int a)
{
    if(a<=2) return false;
    for(int i=2; i*i<=a; i++)
        if(a%i==0) return false;
    return true;
}

int gcd(int a, int b)
{
    return b==0 ? a : gcd(b, a%b);
}
int sums(int a)
{
    int sum = 0;
    while(a!=0)
    {
        sum += (a%10);
        a/=10;
    }
    return sum;
}

int main()
{
    int n, k, m;

    cin >> n;
    for(int i=0; i<n; i++)
    {
        scanf("%d %d", &k, &m);
        printf("Case %d\n", i+1);
        int left = pow(10,k-3), right = pow(10,k-2)-1, flag = 0;
        for(int i=left; i<=right; i++)
        {
            int mm = sums(i*100+99), mn = sums(i*100+100);
            if(mm==m && isprime(gcd(mm,mn)))
            {
                printf("%d %d\n", mn, i*100+99);
                flag = 1;
            }
        }
        if(!flag)
            printf("No Solution\n");
    }

    return 0;
}

原因分析

  • 前置条件
    • K (3
    • m (1
      • the sum of all the digits of A is m;
      • the sum of all the digits of A+1 is n;
      • the greatest common divisor of m and n is a prime number which is greater than 2.
    • N (≤5)
  • 分析优化
    • m最大值: 89,n最大值: 90
      • 计算90以内m、n公共最大除数,该除数是大于2的质数
        • m+1必定存在进位,否则无结果
        • 条件转化1: 进位等价于计算m以多少个数字9结尾
          • 条件转化2: x个9结尾,则有(m-n+1)%9==0
            • 最小差值: 17,即以99结尾
    • 计算代码
      #include 
      using namespace std;
      bool isprime(int a)
      {
          if(a<=2) return false;
          for(int i=2; i*i<=a; i++)
          {
              if(a%i==0) return false;
          }
      
          return true;
      }
      int gcd(int a, int b)
      {
          return b==0 ? a: gcd(b, a%b);
      }
      int main()
      {
      
          for(int i=1; i<90; i++)
          {
              for(int j=i+1; j<90; j++)
              {
                  int gcds = gcd(i,j);
                  if(isprime(gcds) && (j-i+1)%9==0 )
                      printf("%d %d %d\n", i,j, j-i);
              }
          }
      
          return 0;
      }
      
    • 计算结果
      5 40 35
      5 85 80
      7 42 35
      10 45 35
      11 55 44
      13 39 26
      14 49 35
      15 50 35
      17 34 17
      20 55 35
      21 56 35
      25 60 35
      28 63 35
      30 65 35
      33 77 44
      34 51 17
      39 65 26
      40 75 35
      42 77 35
      45 80 35
      49 84 35
      50 85 35
      51 68 17
      68 85 17
      

其他链接

  • dfs剪枝
  • 暴力打表

你可能感兴趣的:(PAT,2019年秋季考试,7-1,Forever,简单数学,算法比赛相关,PAT(甲级))