[C++组合数例题]无关的元素

题目描述

对于给定的n个数a1,a2,...,an,依次求出相邻两数之和,将得到一个新数列。重复上述操作,最后结果将变成一个数。问这个数除以m的余数与哪些数无关?

例如n=3,m=2时,第一次求和得到a1+a2,a2+a3,再次求和得到a1+2a2+a3,它除以2的余数和a2无关。

输入

第1行:2个整数n和m(1<=n<=10^5, 2 <=m<=10^9)

输出

按升序列出与m无关的元素的序号,每行1个。

若与全部元素都有关,输出0

样例输入

5 3

样例输出

3

题解

经过计算可以发现,在最后的表达式中,a1~an的系数就是杨辉三角第n行的数,而我们知道杨辉三角第n行第k个数就等于C(n-1,k-1)。因为C(n-1,0)和C(n-1,n-1)同杨辉三角每一行首尾两个数一样是1,所以不用管它们。那么就需要找C(n-1,1)~C(n-1,n-2)中可以被m整除的数。(以下的n和k都没有-1,但是影响不大,代码中算n-1、k-1就行)

由公式C(n,k)=\frac{n!}{k!(n-k)!}  可知  C(n,k+1)=\frac{n!}{k!(k+1)\frac{(n-k)!}{n-k}}=\frac{n!}{k!(n-k)!}*\frac{n-k}{k+1}=C(n,k)*\frac{n-k}{k+1} ,

所以C(n,k)=C(n,k-1)*\frac{n-k+1}{k} ,而C(n,0)等于1,然后就可以递推了。但是推出来的数太大,计算又不方便,所以把它表示为整数的唯一分解形式。设m=x{_{1}}^{a{_{1}}}*x{_{2}}^{a{_{2}}}*……,x是m的质因数,a是每个质因数的指数。

把每个C(n,k)都表示成这种质因数分解的形式,那么如果C(n,k)的x{_{i}}的指数小于m的,而x又都是质数,所以C(n,k)的分解中就没有其他任何数可以把m多出来的x{_{i}}约掉了,所以此C(n,k)就不能被m整除。

因为C(n,k)=C(n,k-1)*\frac{n-k+1}{k} ,所以C(n,k)的分解就是在前一个数C(n,k-1)的分解中,加上n-k+1的分解的各个质因数的指数,减去k的分解的各个质因数的指数。(有数学基础的人应该听得懂)

详见代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
int n,i,j,num[50000],cnt1[50000],cnt2[50000],ans[50000],len,l;
long long m;
inline void fenjie(){
    for(long long i=2;i<=m;i++){
        if(m%i==0){
            num[++len]=i;
            while(m%i==0)m/=i,cnt1[len]++;
        }
    }
    if(m>1)num[++len]=m,cnt1[len]=1;
}
inline bool ac(int n,int k){//C(n,k)=(n-k+1)/k*C(n,k-1)
    int x=n-k+1,y=k;
    for(int i=1;i<=len&&(num[i]<=x||num[i]<=y);i++){
        while(x%num[i]==0&&x){
            x/=num[i],cnt2[i]++;
        }
        while(y%num[i]==0&&y){
            y/=num[i],cnt2[i]--;
        }
    }
    for(int i=1;i<=len;i++)
        if(cnt1[i]>cnt2[i])return 0;
    return 1;
}
int main()
{
    scanf("%d%lld",&n,&m);
    fenjie();
    for(i=1;i<n-1;i++)
        if(ac(n-1,i))
            ans[++l]=i+1;
    if(l==0)puts("0");
    else
        for(i=1;i<=l;i++)
            printf("%d\n",ans[i]); 
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值