【线性筛 && 全排列】SP 8591 题解

题意

给定一个数 $n$,请求出将 $n$ 拆散后,可以组成的数字中(无前导零的)质数的个数。

思路

First 排列

此题首先需要找出将 $n$ 拆散后的所有没有前导零的排列。

那排列怎么求呢?

有一个 STL:next_permutation,可以求出一个数组的下一个排列。

用法:next_permutation(a + x,a + y)

表示求出 $a$ 数组从地址 $x$ 到 $y$ 变化成其的下一个排列。

Second 判断质数

显然,这道题如果单纯的一个一个判断素数是不行的。

这时候需要用到欧拉筛了,它可以线性预处理出一个范围内所有的质数,以及一个数是不是质数,此题 $n \le 10^7$ 可以通过。

Code

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

#define int long long
#define db double
#define M 10000010

#define For(i, j, k) for (int i = j; i <= k; i++)
#define Rep(i, j, k) for (int i = j; i >= k; i--)
#define mem(a, b) memset(a, b, sizeof a)
#define INF 0x3f3f3f3f
#define LNF 0x3f3f3f3f3f3f3f3f
#define endl '\n'
#define IOS (ios::sync_with_stdio(0), cin.tie(0), cout.tie(0))

int num;
int a[10];

bool is_pri[M];
int prime[M];
int cnt;

void euler(int n)//欧拉筛
{
    memset(is_pri, true, sizeof(is_pri));
    is_pri[1] = false; 
    for(int i = 2; i <= n; ++i)
    {
        if(is_pri[i]) prime[++cnt] = i;
        for(int j = 1; j <= cnt && i * prime[j] <= n; ++j)
        {
            is_pri[i * prime[j]] = false;
            if(i % prime[j] == 0) break;
        }
    }
}

signed main(){
    IOS;
    euler(M - 10);//预处理1e7
    int t;
    cin >> t;
    while(t --){
        cin >> num;
        int w = 0,ans = 0;
        while(num) a[++w] = num % 10,num /= 10;
        sort(a + 1,a + 1 + w);//注意得从最小的排列开始,不然枚举不完
        do{
            int p = 0;
            Rep(i,w,1){
                p = p * 10 + a[i];
            }
            if(is_pri[p] && (int)log10(p) + 1 == w) ans ++;
        } while(next_permutation(a + 1,a + 1 + w));//当没有下一个排列是,函数返回false,否则ture
        cout << ans << endl;
    }
    return 0;
}
posted @ 2023-08-14 20:31  固态H2O  阅读(5)  评论(0编辑  收藏  举报  来源