1009: 密码题目地址
时间限制: 1 Sec 内存限制: 64 MB
题目描述
小翔同学的宿舍WIFI添加了密码,密码每天都会变更。而小翔每天都会给蹭网的同学们提供密码提示。现在请你根据密码提示,编写程序破译密码。
已知密码提示给出了n个整数 a1,a2,…,an,以及一个整数 t(t小于n)。从这n个整数中任选t个相加,可分别得到一系列的和。例如当 n=4,t=3,4 个整数分别为 3,7,12,19 时,可得全部组合的和分别为:
3+7+12=22 3+7+19=29 7+12+19=38 3+12+19=34。
而和为素数的个数即为小翔宿舍WIFI的密码。
例如上例,只有一种的和为素数:3+7+19=29,于是密码即为1。
输入
n , t (1<=n<=20,t<n)
a1,a2,…,an (1<=ai<=5000000)
输出
一个整数(即为密码)。
样例输入
4 3
3 7 12 19
样例输出
1
思路:本题首先打表产生素数;然后再递归产生组合数,即n个数中选取t个数,然后将产生的组合数相加根据素数表验证是否为素数,并统计结果
#include <iostream>
#include <cstring>
#include <cmath>
#include <fstream>
using namespace std;
int prime[100005]; //素数表
int data[21];
int cnt, t;
void getPrime() //产生素数表
{
prime[1] = false;
int sq = sqrt(100005+0.5);
for(int i = 2; i <= sq; i ++)
{
if(!prime[i])
{
continue;
}
for(int j = i + i; j < 100005; j += i)
{
prime[j] = false;
}
}
}
void f(int c[], int t) //统计结果
{
long sum = 0;
for(int i = 0; i < t; i ++)
{
sum += c[i];
//cout << c[i] << " ";
}
//cout << sum << endl;
if(prime[sum])
{
cnt ++;
}
}
//产生组合数,arr为原始数组,n为数组的个数,c为储存组合数数组,t为选取数的个数,i为当前选取的数组的位置,num为当前剩余需要选的数字个数
void com(int arr[], int n, int c[], int t, int i, int num)
{
if(num == 0)
{
f(c, t);
}
else
{
for(int j = i; j < n-num+1; j ++)
{
c[t-num] = arr[j];
//cout << arr[j] << " " << c[t-num] << endl;
com(arr, n, c, t, j+1, num-1);
}
}
}
int main()
{
std::ios::sync_with_stdio(false);
std::cin.tie(0);
//ifstream cin("data.in");
memset(prime, true, sizeof(prime));
getPrime();
int n;
while(cin >> n)
{
cin >> t;
int c[21];
cnt = 0;
for(int i = 0; i < n; i ++)
{
cin >> data[i];
//cout << data[i] << endl;
}
com(data, n, c, t, 0, t);
cout << cnt << endl;
}
return 0;
}