1. 程式人生 > >irrelevant Elements (組合數學)uva-1635

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;
}