题目链接:https://www.luogu.com.cn/problem/P1036

题目大意: n个数中选择k个求和,问结果有几个素数。

思路: C(n,k)种可能,每种都需要遍历到,考虑到n <= 20,1<xi <5e6,可以用DFS遍历所有可能。接下来就是判断结果是不是素数,怎么做,2-sqrt(ans)能否可行?计算最差情况,n = 20,k = 10,xi = 5e6 或 n = 2-,k = 20,xi = 5e6,素数判定最大是1E8,次数是18万多(https://zh.numberempire.com/combinatorialcalculator.php),应该够了,可以试试。

但是我也这样暴力就没有写文章的意义了,我使用了线性筛得出所有的1E8的素数,去二分查找判定,用以确定结果是否为素数,计算为1E8,查找,log2(1E8),不到32.

具体实现,上AC代码:

#include<bits/stdc++.h>
#define fori(i,a,b) for(int i = a;i < b;i++)
#define mod 1000000007
#define ll long long
#define pi acos(-1)
#define ford(i,a,b) for(int i = a;i >= b;i--)
#define fast_input() ios::sync_with_stdio(0)
#define INF 0x3f3f3f3f
#define maxn 10000005
using namespace std;
char flag[maxn]; 
int prime[maxn / 2 + 1];
int cnt = 0;
int n,k;
int num[22];
int ans;
void Euler(int* prime,char*vis,int n,int &cnt){
    for(int i=2;i<=n;i++){
        if(!vis[i]) prime[++cnt]=i;
        for(int j=1;j<=cnt&&i*prime[j]<=n;j++){
            vis[i*prime[j]]=1;
            if(i%prime[j]==0)
            break;
        }
    }
}

int check(int num){
	int t = lower_bound(prime,prime + cnt,num) - prime;
	if(cnt > t && prime[t] == num) return 1;
	else return 0;
}

void DFS(int i,int j,int sum){
	if(i == n || j == k){
		if(j == k) {
			if(check(sum)) ans++;
		}
		return;
	} 
	DFS(i + 1,j + 1,sum + num[i]);
	DFS(i + 1,j,sum);
}

int main(){
	ans = 0;
	Euler(prime,flag,maxn,cnt);
	cin>>n>>k;
	fori(i,0,n)
		cin>>num[i];
	DFS(0,0,0);
	cout<<ans<<endl;
	return 0;
}

 

如有不足或不解之处,欢迎留言或联系QQ2339814485.