1091. Tmutarakan Exams
Memory limit: 64 MB
Input
Output
Sample
input | output |
---|---|
3 10 |
11 |
题意:
New Tmutarakan大学培养在心算方面一流的专家。要进入大学学习您必须能熟练地进行计算。其中一个系的入学考试如下:考生被要求找出K个不同的数字使他们有一个大于1的公约数。所有的数字都不能大于一个指定的数字S。数字K和S在考试开始时给出。为了避免抄袭(这个系是大学里最有名望的!),各组解只能被承认一次(承认最先提交它的人)。
去年,这些数字是K=25和S=49,但是不幸地,没有人能通过考试。并且,它后来被系里最有头脑的人证明了,并不存在一组数字可以满足那些规律。今年为了避免困窘,教务长请求您的帮忙。您要找到K个不同的数字使他们有一个大于1的公约数。所有的数字都不能大于一个指定的数字S。当然,这些解的数量应该与系的新招学生的最大数目相等。
输入格式
输入包含数字K和S (2≤K≤S≤50)。
输出格式
您应该输出系的新学生的最大的可能的数量(也就是解的数量)。如果这个数字不大于10000,请输出这个数字,否则您应该输出10000。
思路:
题目的大意是给出k, s,就在s间的k个不同数的公因子大于1, 我们以 k = 3, s = 25 为例:
首先用一张素数表, 避免有些数的重复计算:
int prime[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43,47, 53 };
因为所有比1大的数都可以由素数相乘得出, 但素数的因子就只有它本身和1,所以可以避免很多不必 要的计算:
在2到25之间有
1: 25/2 = 12个2的倍数 , 所以算出 combination(12, 3)= 220, 得出所有2的倍数3个数一组 的组合
2: 25/3 = 8 个3的倍数, 所以算出combination(8, 3) = 56, 得出 所有3的倍数 3个一组的组合;
3: 25 / 5 = 5 个5 的倍数,所以算出combination(5, 3) = 10
4: 25 / 7 = 3 个 7的倍数,所以算出combination(3,3) = 1
5: 25 / 11 = 2 个11的倍数,所以组合数不够, 跳出循环
结果= 220 + 56 + 10 + 1
但是: 有些组合是被我们计算了2次, 所以应该被减去, 比如:
2 的倍数有2, 4, 6 , 8, 10 ,12, ..........
3的倍数有3, 6 , 9, 12, 15, 18..........
所以6, 12....被重复计算了........然后:
2~~~~~25之间有25 / (2 *3) = 4 , combination (4,3) = 4,所以结果要减去4, 然后继续,看还有不?
代码1:

1 #include <iostream> 2 #include <string> 3 #include<cstring> 4 #include <queue> 5 #include <vector> 6 #include <map> 7 #include <algorithm> 8 #include <cmath> 9 #include <cstdio> 10 11 12 13 using namespace std; 14 15 int kiss[3*100000+5]={0}; 16 17 18 int zuhe(int n,int r) 19 { 20 if(n==0) 21 return 0; 22 if(r==0) 23 return 1; 24 if(r==1) 25 return n; 26 if(r==n) 27 return 1; 28 return zuhe(n-1,r)+zuhe(n-1,r-1); 29 } 30 31 32 int main() 33 { 34 int k,s; 35 cin>>k>>s; 36 long long sum=0; 37 int prime[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53}; 38 // int sgin=0; 39 int i; 40 for(i=0;i<16;i++){ 41 if(s/prime[i]<k){ 42 break; 43 } 44 else{ 45 sum+=zuhe(s/prime[i],k);//计算组合数,进行统计,按质数的进行哈希式的划分 46 } 47 } 48 for(i=0;i<15;i++){ 49 for(int j=i+1;j<16;j++){ 50 sum-=zuhe(s/(prime[i]*prime[j]),k);//减去冗余的项 51 } 52 } 53 sum=sum>10000?10000:sum;//注意输出的要求 54 cout<<sum<<endl; 55 return 0; 56 }
代码2:

1 #include <iostream> 2 #include <string> 3 #include<cstring> 4 #include <queue> 5 #include <vector> 6 #include <map> 7 #include <algorithm> 8 #include <cmath> 9 #include <cstdio> 10 11 12 13 using namespace std; 14 15 int kiss[55][55]={0}; 16 17 18 19 20 int main() 21 { 22 int k,s; 23 cin>>k>>s; 24 long long sum=0; 25 int prime[]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47,53}; 26 // int sgin=0; 27 int i; 28 memset(kiss,0,sizeof(kiss)); 29 for(i=0;i<52;i++){ 30 kiss[i][0]=1; 31 kiss[i][i]=1; 32 } 33 kiss[0][0]=0; 34 for(i=2;i<=50;i++){ 35 for(int j=1;j<i;j++){ 36 kiss[i][j]=kiss[i-1][j-1]+kiss[i-1][j]; 37 } 38 } 39 for(i=0;i<16;i++){ 40 if(s/prime[i]<k){ 41 break; 42 } 43 else{ 44 sum+=kiss[s/prime[i]][k];//计算组合数,进行统计,按质数的进行哈希式的划分 45 } 46 } 47 for(i=0;i<15;i++){ 48 for(int j=i+1;j<16;j++){ 49 sum-=kiss[s/(prime[i]*prime[j])][k];//减去冗余的项 50 } 51 } 52 sum=sum>10000?10000:sum;//注意输出的要求 53 cout<<sum<<endl; 54 return 0; 55 }