20241124每日一题洛谷P1036

普及-每日一题洛谷P1036

题目描述

已知 \(n\) 个整数 \(x_1,x_2,\cdots,x_n\),以及 \(1\) 个整数 \(k\)\(k<n\))。从 \(n\) 个整数中任选 \(k\) 个整数相加,可分别得到一系列的和。例如当 \(n=4\)\(k=3\)\(4\) 个整数分别为 \(3,7,12,19\) 时,可得全部的组合与它们的和为:

\(3+7+12=22\)

\(3+7+19=29\)

\(7+12+19=38\)

\(3+12+19=34\)

现在,要求你计算出和为素数共有多少种。

例如上例,只有一种的和为素数:\(3+7+19=29\)

输入格式

第一行两个空格隔开的整数 \(n,k\)\(1 \le n \le 20\)\(k<n\))。

第二行 \(n\) 个整数,分别为 \(x_1,x_2,\cdots,x_n\)\(1 \le x_i \le 5\times 10^6\))。

输出格式

输出一个整数,表示种类数。

样例输入

4 3
3 7 12 19

样例输出

1

经典的DFS搜索问题,从 \(n\) 个数中选出 \(k\) 个数,使他们的和为素数,计算素数的个数

因为每个数只能选一次,而且计算的是他们的和,所以选数的顺序没有区别

就要做到不重不漏,我们每次搜索下一个数时,就要从前一个数之后开始寻找:

void dfs(int x,int st){//x表示当前我们考虑的是第几个组合数,st表示这次选数从多少开始选
    
    if (x>k){//当我们考虑到第k个组合数之后时,触碰到边界返回
        if (prime(sum))//如果是素数,答案加1
            ans++;
        return ;
    }
    
    for (int i=st;i<=n;i++){//从第st个数开始往后查找
        sum+=a[i];//计算组合数之和
        dfs(x+1,i+1);//递归查找第x+1个组合数
        sum-=a[i];//回溯复位
    }
}

因为每次都从上一个组合数之后的数开始查找,我们选出来的数构成了一个下标严格单调递增的序列

该序列的元素不会重复,即不会回头选我们前面已经选过了的数,组合方案有 \(C_k^n\)

完整代码:

#include <stdio.h>

int n,k,sum,ans;
int a[22];

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

void dfs(int x,int st){
    
    if (x>k){
        if (prime(sum))
            ans++;
        return ;
    }
    
    for (int i=st;i<=n;i++){
        sum+=a[i];
        dfs(x+1,i+1);
        sum-=a[i];
    }
}

int main()
{
    scanf("%d %d",&n,&k);
    for (int i=1;i<=n;i++) scanf("%d",&a[i]);
    dfs(1,1);
    printf("%d",ans);
    return 0;
}
posted @ 2024-11-27 20:37  才瓯  阅读(41)  评论(0)    收藏  举报