题目链接:Irrelevant Elements UVA - 1635
Translation:
题意见https://vjudge.net/problem/UVA-1635
Solution:
唯一分解定理,杨辉三角迭代公式 Cnk=n−k−1kCnk−1 C k n = n − k − 1 k C k − 1 n
根据杨辉三角的迭代公式即可很容易得出最后一项的每一项系数。根据是否能够整除m,就可以得出这一项是否跟最后的结果有关。但是问题在于最后一项的数据范围太大,必须用高精度才能保存。所以直接对m取余来求解是行不通的。所以就必须用唯一分解定理:对m进行素因子分解,然后对于每一项m的素因子,求其在每一项Ci中的次数(对Ci也进行了唯一分解),如果一旦有在Ci中的次数<在m中的次数,那么就可以断定这个Ci肯定不能整除m.
据此就可以得出结果。
note:
1:注意最后判断能否整除 m 时,当在Ci中的次数>=在m中的次数并不能说明就一定能整除m。因为还有其它的素因子未判断。
2:这道题可以总结出一个利用唯一分解定理判断能否整除m的一个方法,这样就不需要高精度了。
#include<iostream>
#include<string>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<queue>
#include<stack>
#include<map>
#include<iomanip>
#define ll long long
using namespace std;
const int maxn = 100000 + 2;
int m, n; //n个数
bool flag[maxn]; //表示第i个元素无关
void getPrimes(vector<int>& p) { //求出m的所有素因子
int tmp = m;
int t = floor(sqrt(tmp) + 0.5);
for(int i = 2; i <= t; i++) {
if(tmp % i == 0) {
p.push_back(i);
while(tmp % i == 0) tmp /= i;
}
}
if(tmp > 1) p.push_back(tmp);
}
//c(n, k) = c(n, k-1) * (n-k+1) / k
int main()
{
while(scanf("%d%d",&n,&m) != EOF) {
memset(flag, 0, sizeof(flag));
vector<int> primes;
getPrimes(primes); //求出m的所有素因子;
--n;
for(int i = 0; i < primes.size(); i++) {
int tp = primes[i];
int me = 0, pe = 0;
int tmp = m;
while(tmp % tp == 0) { tmp /= tp; me++; } //求出这个素因子的次数
for(int k = 1; k < n; k++) { //第一项和最后一项都是1,不用计算
int up = n - k + 1;
while(up % tp == 0) { up /= tp; pe++; }
int down = k;
while(down % tp == 0) { down /= tp; pe--; }
if(pe < me) flag[k] = true; //第k+1个数有关,note
}
}
vector<int> ans;
for(int k = 1; k < n; k++)
if(!flag[k]) ans.push_back(k+1); // 编号从1开始
cout << ans.size() << "\n";
if(!ans.empty()) {
cout << ans[0];
for(int i = 1; i < ans.size(); i++) cout << " " << ans[i];
}
cout<<endl;
}
return 0;
}