http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=51196
紫书P320;
题意:给定n个数a1,a2····an,依次求出相邻两个数值和,将得到一个新数列,重复上述操作,最后结果将变为一个数,问这个数除以m的余数与那些数无关?例如n=3,m=2时,第一次得到a1+a2,a2+a3,在求和得到a1+2*a2+a3,它除以2的余数和a2无关。1=<n<=10^5, 2=<m<=10^9
其实就是杨辉三角的某一行有几个能整除m,求C(0,n - 1),C(1, n - 2)... C(n - 1, n - 1)中那几个能整除m
解题思路:
1、首先我们可以发现对于给定的n其实每项的系数就是C(n-1,i-1),所以我们只需要找到每项的系数对m取余是否为0即可
2、由于m的取值范围为10^9,所以我们只需要筛选 √(10^9)的素数,然后对m进行分解;如果分解后m>1,说明当前m的是原m的一个素数,而且m> √(10^9),因此我们只需记录它即可
3、由组合数的递推公式C(k, n) = (n - k + 1) / k * C(k - 1, n),而这道题n = n - 1;首项是一,可以直接从第二项即k = 1: (n - 1 ) - k + 1 / k开始判断是否能整除m,分子能整除素数元素个数就减一,分母能整除就+1,如果对于任意一个素数对应的指数 >= 1,就说明不能整除
收获:
每个整数的唯一分解式项数不多(long long 类型的数值最多20项,前21个素数相乘long long就溢出了)
1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 using namespace std; 6 const int Max = 40000; 7 8 int factor[20],nfactor[20],num_factor,flag_factor[100000 + 10]; 9 int count_prime,prime[Max + 5],flag[Max + 5]; 10 void get_prime() 11 { 12 memset(flag, 0, sizeof(flag)); 13 count_prime = 0; 14 for(int i = 2; i <= Max; i++) 15 { 16 if(flag[i] == 0) 17 { 18 flag[i] = 1; 19 prime[++count_prime] = i; 20 for(int j = 2; j <= Max / i; j++) 21 { 22 flag[i * j] = 1; 23 } 24 } 25 } 26 } 27 28 void get_factor(int m) 29 { 30 num_factor = 1; 31 memset(nfactor, 0, sizeof(nfactor)); 32 memset(factor, 0, sizeof(factor)); 33 for(int i = 1; i <= count_prime; i++) 34 { 35 if(m < prime[i]) 36 break; 37 if(m % prime[i] == 0) 38 { 39 factor[num_factor] = prime[i]; 40 while(m % prime[i] == 0 && m) 41 { 42 nfactor[num_factor]++; 43 m = m / prime[i]; 44 } 45 num_factor++; 46 if(m == 0 || m == 1) 47 break; 48 } 49 } 50 if(m > 1) 51 { 52 factor[num_factor] = m; 53 nfactor[num_factor]++; 54 num_factor++; 55 } 56 } 57 bool check(int x, int y) 58 { 59 bool check_flag = true; 60 for(int i = 1; i < num_factor; i++) 61 { 62 while(x % factor[i] == 0 && x) 63 { 64 x = x / factor[i]; 65 nfactor[i]--; 66 } 67 while(y % factor[i] == 0 && y) 68 { 69 y = y / factor[i]; 70 nfactor[i]++; 71 } 72 if(nfactor[i] >= 1) 73 { 74 check_flag = false; 75 //break; 要不得,即使不能整除,也要约分完,因为下一个受这一个的影响 76 } 77 } 78 return check_flag; 79 } 80 int main() 81 { 82 int n,m; 83 get_prime(); 84 while(scanf("%d%d", &n, &m) != EOF) 85 { 86 get_factor(m); //对m分解 87 int cnt = 0, ends = 0; 88 memset(flag_factor, 0, sizeof(flag_factor)); 89 for(int i = 1; i <= n; i++) 90 { 91 if( check(n - i, i) ) //原型就是 (n - 1 - i + 1) / i 92 { 93 flag_factor[i + 1] = 1; 94 ends = i + 1; 95 cnt++; 96 } 97 } 98 printf("%d\n", cnt); 99 if(cnt > 0) 100 { 101 for(int i = 1; i < ends; i++) 102 if(flag_factor[i]) 103 printf("%d ", i); 104 printf("%d", ends); 105 } 106 printf("\n"); 107 } 108 return 0; 109 }