ural 1091. Tmutarakan Exams(容斥原理)

1091. Tmutarakan Exams

Time limit: 1.0 second
Memory limit: 64 MB
University of New Tmutarakan trains the first-class specialists in mental arithmetic. To enter the University you should master arithmetic perfectly. One of the entrance exams at the Divisibility Department is the following. Examinees are asked to find  K different numbers that have a common divisor greater than 1. All numbers in each set should not exceed a given number  S. The numbers  Kand  S are announced at the beginning of the exam. To exclude copying (the Department is the most prestigious in the town!) each set of numbers is credited only once (to the person who submitted it first).
Last year these numbers were  K=25 and  S=49 and, unfortunately, nobody passed the exam. Moreover, it was proved later by the best minds of the Department that there do not exist sets of numbers with the required properties. To avoid embarrassment this year, the dean asked for your help. You should find the number of sets of  K different numbers, each of the numbers not exceeding  S, which have a common divisor greater than 1. Of course, the number of such sets equals the maximal possible number of new students of the Department.

Input

The input contains numbers  K and  S (2 ≤  K ≤  S ≤ 50).

Output

You should output the maximal possible number of the Department's new students if this number does not exceed 10000 which is the maximal capacity of the Department, otherwise you should output 10000.

Sample

inputoutput
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 }
View Code

代码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 }
View Code

 

 

转载于:https://www.cnblogs.com/zhangchengbing/p/3425684.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值