UVA 1635 - Irrelevant Elements(唯一分解+组合数)

题目链接 https://cn.vjudge.net/problem/UVA-1635

【题意】
对于给定的n个数a[1],a[2],…a[n],依次求出相邻两项之和,得到一个新数列.重复这个操作最后结果变成一个数,问这个数对m取模后与原数列中的哪些项无关?比如n=3,m=2时,第一次求和得到a1+a2,a2+a3,再求和得到a1+2*a2+a3,它对2取模之后就和第二项无关了(1<=n<=1e5,2<=m<=1e9)

【思路】
随便推算几个式子就能发现a[1],a[2]…a[n]不断求和之后最终得到的数字是它们的一个线性组合,而且每一项a[i]前面的系数是C(n-1,i-1),问题转换为求C(n-1,0),C(n-1,1)…C(n-1.n-1)中哪些是m的倍数

可以对数字m先唯一分解,之后根据组合数的递推式

Cnk=nk+1kCnk1
来递推所有项,注意输出格式即使没有符合要求的项也要在第二行输出一个换行

#include<bits/stdc++.h>
using namespace std;

const int maxn=50050;

vector<int> prime,ans;
int n,m,num;
int cnt[maxn],c[maxn];

void calc(){
    num=0;
    prime.clear();
    memset(cnt,0,sizeof(cnt));
    int sq=sqrt(m)+0.5;
    for(int i=2;i<=sq;++i){
        if(m%i==0){
            prime.push_back(i);
            while(m%i==0){
                m/=i;
                ++cnt[num];
            }
            ++num;
        }
    }
    if(m>1){
        prime.push_back(m);
        ++cnt[num];
        ++num;
    }
}

bool solve(int k){
    int x=n-k+1;
    int y=k;
    for(int i=0;i<num;++i){
        while(x%prime[i]==0){
            x/=prime[i];
            ++c[i];
        }
        if(x==1) break;
    }
    for(int i=0;i<num;++i){
        while(y%prime[i]==0){
            y/=prime[i];
            --c[i];
        }
        if(y==1) break;
    }
    for(int i=0;i<num;++i){
        if(c[i]<cnt[i]) return false;
    }
    return true;
}

int main(){
    while(scanf("%d%d",&n,&m)==2){
        if(n<=2) {puts("0\n");continue;}
        calc();
        --n;
        ans.clear();
        memset(c,0,sizeof(c));
        for(int i=1;i<n;++i){
            if(solve(i)) ans.push_back(i+1);
        }
        printf("%d\n",ans.size());
        if(ans.empty()) puts("");
        for(int i=0;i<ans.size();++i) printf("%d%c",ans[i],i+1==ans.size()?'\n':' ');
    }
    return 0;
}
posted @ 2018-08-21 22:26  不想吃WA的咸鱼  阅读(110)  评论(0编辑  收藏  举报