irrelevant Elements (组合数学)uva-1635

题目大意:

  对于给定的n个数a1,a2,a3....an,一次求出相邻两个数之和,将得到一个新的数列。重复上述操作,最后结果将变成一个数。问这个数除以m的余数与那些数无关?例如n=3,m=2时,第一次求和结果a1+a2,a2+a3,在求和a1+2a2+a3,它除以2的余数和a2无关,1<=n<=10^5,2<=m<=10^9

题解:(紫书p320)

显然最后的求和式是a1,a2,a3....an的线性组合。设ai的系数为f(i),则和式除以m的余数与ai无关,当且仅当f(i)是i的倍数。列如,当n=5时,最后结果为a1+4a2+6a3+4a4+a5

其中系数为1 4 6 4 1,可见是杨辉三角的第5行。那么通过定理,最后ai的系数是C(i-1,n-1)。这样问题就变成了C(0,n-1),C(1,n-1)....C(n-1,n-1)中有几个是m的倍数。

紫书上有一个递推结论C(k,n)=(n-k+1)/k*C(k-1,n),如果直接去求C(i-1,n-1)会爆long long 。那么就用唯一分解定理先将m分解了,然后在对C(i-1,n-1)分解了,看他们的素因子的指数是否合理,如果合理就是倍数关系。所谓合理就是C(i-1,n-1)的每一个素因子指数都要大于等于m的素因子指数

#include <bits/stdc++.h>
#define N 100005

using namespace std;

int prime[N];
int vis[N];
int a[N];
int fec[10000][2];
int fecn[10000];

int fec_num;
int pri_num;


void putm(int m)
{
    fec_num=0;
    for(int i=2; i*i<=m; i++)
    {
        if(m%i==0)
        {
            int num=0;
            while(m%i==0)
            {
                m=m/i;
                num++;
            }
            fec[fec_num][0]=i;
            fec[fec_num++][1]=num;
        }
       // if(m==1)break;
    }
    if(m>1)
    {
        fec[fec_num][0]=m;
        fec[fec_num++][1]=1;
    }
}
bool cheak(int n,int k)
{
    int x=n-k+1;
    int y=k;
    for(int i=0;i<fec_num;i++)
    {
        int p=fec[i][0];
        int &q=fecn[i];
        while(x%p==0)
        {
            x=x/p;
            q++;
        }
        while(y%p==0)
        {
            y=y/p;
            q--;
        }
    }
    for(int i=0;i<fec_num;i++)
    {
        if(fecn[i]<fec[i][1])return false;
    }
    return true;
}
int main()
{
    int n,m;
    int cnt;
    while(cin>>n>>m)
    {
        putm(m);
        cnt=0;
        memset(fecn,0,sizeof(fecn));
        for(int i=1;i<n;i++)
        {
            if(cheak(n-1,i))
            {
                a[cnt++]=i+1;
            }
        }
        printf("%d\n",cnt);
        for(int i=0;i<cnt;i++)
        {
            if(i==0)printf("%d",a[i]);
            else printf(" %d",a[i]);
        }
        printf("\n");
    }
    return 0;
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值