题目链接: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.