经过紫书的分析,已经将问题转化为求组合数C(n-1, 0)~C(n-1, n-1)中能够被m整除的个数,并输出编号(这n个数的编号从1开始)
首先将m分解质因数,然后记录下每个质因子对应的指数。
一个没什么用的小优化:因为杨辉三角每一行都是对称的,所以我们可以求出前一半答案,然后根据对称性求出后一半的答案。
需要注意的是,如果答案中有类似C(10, 5)的数,就不要再对称了,会重复的。
这个优化貌似也只能优化0.05s左右。
1 #include <cstdio> 2 #include <cstring> 3 #include <cmath> 4 5 const int maxn = 100000 + 10; 6 int prime[maxn], bad[maxn], e[maxn], ans[maxn]; 7 int p_cnt; 8 9 void prime_factors(int n) 10 { 11 p_cnt = 0; 12 int m = floor(sqrt(n) + 0.5); 13 for(int i = 2; i <= m; ++i) 14 { 15 if(n % i == 0) { prime[p_cnt++] = i; } 16 while(n % i ==0) { e[p_cnt-1]++; n /= i; } 17 } 18 if(n > 1) 19 { 20 prime[p_cnt] = n; 21 e[p_cnt++] = 1; 22 } 23 } 24 25 int main() 26 { 27 int n, m; 28 while(scanf("%d%d", &n, &m) == 2) 29 { 30 memset(prime, 0, sizeof(prime)); 31 memset(bad, 0, sizeof(bad)); 32 memset(ans, 0, sizeof(ans)); 33 memset(e, 0, sizeof(e)); 34 n--; 35 36 prime_factors(m); 37 for(int i = 0; i < p_cnt; ++i) 38 { 39 int p = prime[i]; 40 int need = e[i]; 41 int cur_e = 0; 42 for(int k = 1; k <= n/2; ++k) 43 { 44 int x = n - k + 1; 45 while(x % p == 0) { cur_e++; x /= p; } 46 x = k; 47 while(x % p == 0) { cur_e--; x /= p; } 48 if(cur_e < need) bad[k] = 1; 49 } 50 } 51 52 int ans_cnt = 0; 53 for(int k = 1; k <= n/2; ++k) 54 if(!bad[k]) ans[ans_cnt++] = k; 55 if(ans_cnt) 56 { 57 int p = ans_cnt-1; 58 if(ans[p] * 2 == n) p--; 59 for(int i = p; i >= 0; i--) 60 ans[ans_cnt++] = n - ans[i]; 61 printf("%d ", ans_cnt); 62 printf("%d", ans[0] + 1); 63 for(int i = 1; i < ans_cnt; ++i) printf(" %d", ans[i] + 1); 64 } 65 else puts("0"); 66 printf(" "); 67 } 68 69 return 0; 70 }