2019年PAT秋考B-4天长地久 20分 难点:需要剪枝优化 题型:枚举

88 阅读2分钟

1104 天长地久 - PAT (Basic Level) Practice (中文) (pintia.cn)

这道题因为数的范围太大(最大1e10)要做剪枝,这是刚开始写的代码:


#include <bits/stdc++.h>
using namespace std;

struct node {
    int n, A;
    friend bool operator < (node &a, node &b) {
        if (a.n != b.n) return a.n < b.n;
        return a.A < b.A;
    }
    }T;
vector<node> V;
int N, k, m, sum1, sum2, temp, I, II;

int gcd(int a, int b) {
    if (b == 0) return a;
    return gcd(b, a % b);
}

bool is_prime(int x) {
    if (x <= 2) return 0;
    for (int i = 2; i <= sqrt(x); i++) {
        if (x % i == 0) return 0;
    }
    return 1;
}

int main() {
    cin >> N;

    for (int i = 1; i <= N; i++) {
        V.clear();// 每一轮都要清空
        cout << "Case " << i << '\n';
        cin >> k >> m;

       // if (k * 9 < m) cout << "No Solution\n";
     //   else {
            temp = pow(10, k);
            for (int i = temp / 10; i < temp; i++) {
                sum1 = 0, sum2 = 0, I = i, II = i + 1;
                while (I) {
                    sum1 += I % 10;
                    I /= 10;
                    if (sum1 > m) break;
                }
                

                while (II) {
                    sum2 += II % 10;
                    II /= 10;
                }

                if (sum1 == m && is_prime(gcd(m,sum2))) {
                    
                    T.n = sum2, T.A = i;
                    V.push_back(T);
                }
            }
            sort(V.begin(), V.end());
            if (V.empty()) cout << "No Solution\n";
            for (auto &it : V) {
                cout << it.n << ' ' << it.A << "\n";
            }
        }
   // }
    return 0;
}

image.png

优化

把整体范围剪小,假设本来k是6,也就是要枚举1e6的数,现在我们可以枚举1e4的数,在每个数的末尾加上"99"就可以了(观察样例可以发现每个数的后两位都是"99"”,这样就可以把整体范围缩小了

image.png code

#include <bits/stdc++.h>
using namespace std;

struct node {
    int n, A;
    friend bool operator < (node& a, node& b) {
        if (a.n != b.n) return a.n < b.n;
        return a.A < b.A;
    }
}T;
vector<node> V;
int N, k, m, sum1, sum2, temp, I, II;

int gcd(int a, int b) {
    if (b == 0) return a;
    return gcd(b, a % b);
}

bool is_prime(int x) {
    if (x <= 2) return 0;
    for (int i = 2; i <= sqrt(x); i++) {
        if (x % i == 0) return 0;
    }
    return 1;
}

int main() {
    cin >> N;

    for (int i = 1; i <= N; i++) {
        V.clear();// 每一轮都要清空
        cout << "Case " << i << '\n';
        cin >> k >> m;

        if (k * 9 < m) cout << "No Solution\n";
        else {
            temp = pow(10, k - 2);
            for (int i = temp / 10; i < temp; i++) {
                sum1 = 18, sum2 = 0, I = i, II = i + 1;
                while (I) {
                    sum1 += I % 10;
                    I /= 10;
                    if (sum1 > m) break;
                }


                while (II) {
                    sum2 += II % 10;
                    II /= 10;
                }

                if (sum1 == m && is_prime(gcd(m, sum2))) {

                    T.n = sum2, T.A = i;
                    V.push_back(T);
                }
            }
            sort(V.begin(), V.end());
            if (V.empty()) cout << "No Solution\n";
            for (auto& it : V) {
                cout << it.n << ' ' << it.A << "99\n";
            }
        }
    }
    return 0;
}
#include<bits/stdc++.h>
using namespace std;
int N,k,m;
struct node
{
   int n;
   int a;
}T;
vector<node>v;
bool isprime(int x)
{
   if(x<=2)return false;
   for(int i=2;i*i<=x;i++)
   {
       if(x%i==0)return false;
   }
return true;
}
int gcd(int a,int b)
{
   return b==0?a:gcd(b,a%b);
}
bool cmp(struct node A,struct node B)
{
   if(A.n==B.n)return A.a<B.a;
return A.n<B.n;
}
int main()
{
   cin>>N;
   for(int Case=1;Case<=N;Case++)
   {
       v.clear();
       cout<<"Case "<<Case<<endl;
       cin>>k>>m;
       
       //枚举找一下sum1
       int digits=pow(10,k-2);
       for(int i=digits/10;i<digits;i++)
       {
           int sum1=18,sum2=0,I=i,II=i+1;  //sum1设为18的原因是i的后两位"99"的和为18
           while(I)
           {
               sum1+=I%10;
               I/=10;
               if(sum1>m)break;
           }
           while(II)
           {
               sum2+=II%10;
               II/=10; 
           }
           if(sum1==m&&isprime(gcd(sum2,m)))
           {
               T.n=sum2,T.a=i;
               v.push_back(T);
           }
       }	 
       sort(v.begin(),v.end(),cmp);
       if(v.size()==0)cout<<"No Solution\n";
       else
       {
           for(auto &it:v)
           {
               cout<<it.n<<" "<<it.a<<"99\n";
           }	
       }

   }

return 0;	
} 

image.png