(不一定是每日更新的每日一题)洛谷P1036

审题

分析

        题目要求我们从要求的数中取出几个数并且使其和为质数,乍一看分析起来有点难,因为取数的方法可以有很多种,但是进一步分析,好像和我们以前做过的全排列题目有些类似,但是全排列题目要求是求出某个数以内所有排列,转念一想,和这题是不是有点类似

        那么就可将这题转换为全排列,那么我们是不是可以通过全排列来确定选数,比如题目中3 7 19可以组成素数29,那么我们是不是可以认为下标为0 1 3的数字可以组成素数,这样我们就可以通过全排列时候的下标索取,来获取不同组合的和

        同时我们又要确定某个数是不是素数,这就有很多方法,我用的是比较朴素的O(sqrt(n))复杂度的方法(因为比较简单~),其他有改进的方法肯定更好

        那么当我们交的时候,是不是就正确了呢?答案是不是的

        还是以样例为例子,0 1 3可以组成素数,1 0 3是不是也可以呢?那么问题就来了:如何保证去重?

        有些人会想到用set来去重,再输出set.size(),但是比如29可以是3 7 19组成,也可以是4 6 19组成,这样的话,应该有两种组合方式的情况会被缩减到一种

        解决方法:对于n的全排列,我们发现由同一数字组成的重复的个数是n!,比如例题,由013组成的排列可以有3!=6种,那么我们可以写一个求阶乘的函数来解决这个问题

        综上,该问题就圆满结束了,下面是实现代码

实现代码



#include <bits/stdc++.h>
#define int long long

using namespace std;

const int N=30;

int n,num,cnt;
bool st[N];
int path[N],nm[N];

int di(int x){
if(x==1||x==0) return x;
return x*di(x-1);
}

bool is_primes(int x){
for(int i=2;i<=x/i;i++)
if(x%i==0) return false;
return true;
}

void dfs(int u){
if(u==num) {
int sum=0;
for(int i=0;i<num;i++)
sum+=nm[path[i]];
if(is_primes(sum))
cnt++;
}

for(int i=0;i<n;i++){
if(!st[i]){
path[u]=i;
st[i]=true;
dfs(u+1);
st[i]=false;
}
}
}

signed main(){
cin>>n>>num;

for(int i=0;i<n;i++) cin>>nm[i];
dfs(0);

cout<<cnt/di(num);
return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值