UVA 1635-Irrelevant Elements(唯一分解定理)

探讨给定数列通过连续求和直至只剩单一数值过程中,最终值除以特定数m的余数与哪些初始数无关。通过组合数学原理确定各数在最终结果中的系数,并利用素数分解及模运算特性解决此问题。

原题链接:点击打开链接

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

思路:

1、首先我们可以发现对于给定的n其实每项的系数就是C(n-1,i-1),所以我们只需要找到每项的系数对m取余是否为0即可

2、由于m的取值范围为10^9,所以我们只需要筛选 √(10^9)的素数,然后对m进行分解;如果分解后m>1,说明当前m的是一个素数,而且m> √(10^9),因此我们只需记录它即可

3、根据C(n,k)=C(n,k)*(n-i+1)/i;(根据这个公式我们可以发现C(n,k)*(n-i+1)一定能整除i),对m分解式中的素数进行操作即可,具体见代码

这题虽然不难,但我WA了好几次,花了好久才发现是取消同步的问题,这是个坑,看来不能随便用取消同步o(╯□╰)o

/*************************************************************************
    > File Name: 1635.cpp
    > Author: Clannad
    > Mail: 821199012@qq.com
    > Created Time: Mon 11 July 2016 09:03:28 PM
************************************************************************/
#include <vector>
#include <map>
#include <set>
#include <queue>
#include <stack>
#include <algorithm>
#include <sstream>
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <cstring>
#include<string>
#include <ctime>
using  namespace std;
typedef  long  long  ll;
const int inf=0x3f3f3f3f;
const int maxn=32000;//32000*32000=1024e6;
int prime[maxn+1];
int nprime;
void  getprime(){
    int m=sqrt(maxn+0.5);
    for(int i=2 ; i<m ; i++)if(!prime[i])
        for(int j=i*i ; j<=maxn ; j+=i)prime[j]=1;

    nprime=0;
    for(int i=2 ; i<=maxn ; i++){
        if(!prime[i])
            prime[nprime++]=i;
    }
}
int n,m;
int pm[20];
int km[20];
int cnt;
void init(){
    memset(pm,0,sizeof(pm));
    memset(km,0,sizeof(km));
    cnt=0;
    for(int i=0 ; i<nprime&&m>=prime[i] ; i++){
        if(m%prime[i]==0) {
            pm[cnt]=prime[i];
            while((m%prime[i]==0)&&(m/=prime[i]))
                km[cnt]++;
            cnt++;
        }
        if(n==0||n==1)break;
    }
     if(m>1){
            pm[cnt]=m;
            km[cnt]=1;
            cnt++;
    }
}
bool  getfactors(int x,int y){
    bool f=true;
    for(int i=0 ; i<cnt ; i++){
        while((x%pm[i]==0)&&(x/=pm[i]))
            km[i]--;
        while(y%pm[i]==0&&(y/=pm[i]))
            km[i]++;
        if(km[i]>0)f=false;
    }
    return f;
}
bool flag[100010];
int main(){
//    std::ios::sync_with_stdio(false);
//    #ifndef ONLINE_JUDGE
//        freopen("inF.txt", "r", stdin);
//    #endif
    getprime();
    while(cin>>n>>m){
        init();
        memset(flag,false,sizeof(flag));
        int  ans=0,ends=0;
        for(int i=1 ; i<=n ; i++){
            if(getfactors(n-i,i)){
                flag[i+1]=true;
                ans++;
                ends=i+1;
            }
        }
         printf("%d\n",ans);
         if(ans!=0){
            for(int i=1; i<ends; i++)
                if(flag[i])
                    printf("%d ",i);
            printf("%d",ends);
        }
        printf("\n");
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值