小TT最近学习了高斯消元法解方程组,现在他的问题来了,如果是以下的方程,那么应该如何解呢?
C(n1,m1)==0 (mod M)
C(n2,m2)==0 (mod M)
C(n3,m3)==0 (mod M)
................
C(nk,mk)==0 (mod M)
小TT希望你告诉他满足条件的最大的M
其中C(i,j)表示组合数,例如C(5,2)=10,C(4,2)=6...
输入数据包括多组,每组数据的第一行是一个正整数T(1<=T<=150)表示接下来描述的T个方程
接下来T行,每行包括2个正整数ni,mi (1<=mi<=ni<=100000)
输出一行答案,表示满足方程组的最大M。
//其实题意就是求n个组合数的最大公约数! 对每个组合数素因子分解,然后求求出素因子并集,最后把这些素因子相乘即可!
//本题在一些细节优化上需要做好!自己超时了十余次不断修改优化才AC!
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define min(a,b) (a<b?a:b) #define LL long long #define maxn 100005 #define INF 155 struct NODE { int prime,ans; }node[maxn]; int x[maxn],A[INF],B[INF],m=0,minnum; void isprime() //筛选出100000以内的素因子 { int i,tmp; memset(x,0,sizeof(x)); x[0]=x[1]=1; for(i=2;i<maxn;i++) if(!x[i]) { node[++m].prime=i; tmp=i*2; while(tmp<maxn) x[tmp]=1,tmp+=i; } } void make_ans(int n1,int n2,int n3,int d) { int i,tmp,num; for(i=1;i<=m&&node[i].prime<=minnum;i++) { num=0; //注意3:因为只调用一次函数每次针对单个素因子运算,所以不必要用数组记录,只用变量即可!省去了在之前的for循环中每次对数组清零,这也是本题的最大优化之处,之前没多想,一直TLE. if(node[i].prime<=n1) { tmp=n1; while(tmp) num+=tmp/node[i].prime,tmp/=node[i].prime; } if(node[i].prime<=n2) { tmp=n2; while(tmp) num-=tmp/node[i].prime,tmp/=node[i].prime; } if(node[i].prime<=n3) { tmp=n3; while(tmp) num-=tmp/node[i].prime,tmp/=node[i].prime; } if(d==1) node[i].ans=num; else node[i].ans=min(node[i].ans,num); } } int main() { isprime(); int T,t,i,j; while(~scanf("%d",&T)) { for(i=0;i<maxn;i++) node[i].ans=0; minnum=100001; for(t=1;t<=T;t++) { scanf("%d%d",&A[t],&B[t]); if(A[t]<minnum) //注意1:因为是求组合数的素因子分解并集,显然大于最小的n的素因子不用统计! minnum=A[t]; } for(t=1;t<=T;t++) make_ans(A[t],B[t],A[t]-B[t],t); //注意2:对C(n,m)素因子分解!n!/(m!*(n-m)!)不需要调用三次函数,直接在函数里面针对某个因子做三次运算,自己之前求C(n,m)都是调用三次函数求n!的素因子分解,在这里就很耗时了! LL sum=1; for(i=1;i<=m;i++) if(node[i].ans) for(j=1;j<=node[i].ans;j++) sum*=node[i].prime; printf("%I64d\n",sum); } return 0; }