题目要求:给两个数k和s,在不大于s的数中找出k不想等的数,要求k个数的公约数大于1
题目分析:在不大于s的所有数中,公约数是 i (i>2)的个数为 s/i ,所以求出 i 为素数,c(s/i,k)的所有和 //(c(n,m)表示求组合数)
但是纯粹这样求出后中间就会有重复计算,例如,当k=2,s=12时,公约数为2的数有2,4,6,8,10,12;公约数为3的数有3,6,9,12
这样6和12就重复计算了,所以计算后应减去这部分重复的,利用容斥原理求解即可。
对于求解组合数,求出杨辉三角即可
View Code
#include<iostream> #include<cstring> using namespace std; int p[16]={2,3,5,7,11,13,17,19,23,29,31,37,41,43,47}; int c[30][30]; void Getc() //求出组合数,即杨辉三角 { int i,j; memset(c,0,sizeof(c)); for(i=0;i<26;i++) { for(j=0;j<=i;j++) { if(i==j||j==0) c[i][j]=1; else c[i][j]=c[i-1][j]+c[i-1][j-1]; } } } int main() { int k,s,sum,i,t,num[50]; Getc(); while(cin>>k>>s) { memset(num,0,sizeof(num)); for(t=0;s/p[t]>=k;t++) { num[t]=s/p[t]; } for(i=0,sum=0;i<t;i++) { sum+=c[num[i]][k]; //求出所有的可能的和 } sum-=c[s/6][k]; //减去重复部分,容斥原理 sum-=c[s/10][k]; sum-=c[s/14][k]; sum-=c[s/15][k]; sum-=c[s/21][k]; sum-=c[s/22][k]; if(sum>10000) sum=10000; cout<<sum<<endl; } return 0; }
一些测试数据
View Code
1 2 2 0 2 2 3 0 3 2 4 1 4 2 5 1 5 2 6 4 6 2 7 4 7 2 8 7 8 2 9 9 9 2 10 14 10 2 11 14 11 2 12 21 12 2 13 21 13 2 14 28 14 2 15 34 15 2 16 41 16 2 17 41 17 2 18 52 18 2 19 52 19 2 20 63 20 2 21 71 21 2 22 82 22 2 23 82 23 2 24 97 24 2 25 101 25 2 26 114 26 2 27 122 27 2 28 137 28 2 29 137 29 2 30 158 30 2 31 158 31 2 32 173 32 2 33 185 33 2 34 202 34 2 35 212 35 2 36 235 36 2 37 235 37 2 38 254 38 2 39 268 39 2 40 291 40 2 41 291 41 2 42 320 42 2 43 320 43 2 44 343 44 2 45 363 45 2 46 386 46 2 47 386 47 2 48 417 48 2 49 423 49 2 50 452 50 3 2 0 51 3 3 0 52 3 4 0 53 3 5 0 54 3 6 1 55 3 7 1 56 3 8 4 57 3 9 5 58 3 10 11 59 3 11 11 60 3 12 24 61 3 13 24 62 3 14 39 63 3 15 46 64 3 16 67 65 3 17 67 66 3 18 104 67 3 19 104 68 3 20 143 69 3 21 159 70 3 22 204 71 3 23 204 72 3 24 277 73 3 25 283 74 3 26 349 75 3 27 377 76 3 28 458 77 3 29 458 78 3 30 588 79 3 31 588 80 3 32 693 81 3 33 739 82 3 34 859 83 3 35 880 84 3 36 1061 85 3 37 1061 86 3 38 1214 87 3 39 1281 88 3 40 1470 89 3 41 1470 90 3 42 1732 91 3 43 1732 92 3 44 1945 93 3 45 2063 94 3 46 2294 95 3 47 2294 96 3 48 2631 97 3 49 2646 98 3 50 2952