【UVA1635】哑元

题意

给定n个数a1,a2,...an,依次求出相邻两数之和,将得到一个新数列。重复上述操作,最后结果将变成一个数。问这个数除以m的余数与哪些数无关?例如n=3,m=2时,第一次求和得到a1+a2,a2+a3,再求和得到a1+2a2+a3,它除以2的余数和a2无关。(1 ≤ n ≤ 100 000, 2 ≤ m ≤ 109 )

分析

举的这个例子已经疯狂暗示了,怎么看都是二项式定理啊!!!

二项式定理就不写了,反正就是求组合数了,有一个递推的式子

证明太显然了,直接拆成递推形式一眼就看出来了。于是可以利用它计算出C(n-1,i-1)的每一项,得到ai的系数,再判断一下是不是m的倍数

直接递推太大了,会涉及到高精,于是利用唯一分解定理分解m,再比较各个质因子的指数与C(n-1,i-1)中的指数即可。

代码

  1. #include<bits/stdc++.h>  
  2. using namespace std;  
  3. #define N 100010  
  4. int n,m,cnt;  
  5. int p[N],c[N],ok[N];  
  6. vector<int>ans;  
  7. void divide(int k)  
  8. {  
  9.     cnt=0;  
  10.     memset(p,0,sizeof(p));  
  11.     memset(c,0,sizeof(c));  
  12.     int mx=(int)sqrt(k+1);  
  13.     for(int i=2;i<=mx;i++)  
  14.     {  
  15.         if(k%i==0)  
  16.         {  
  17.             p[++cnt]=i;  
  18.             while(k%i==0)c[cnt]++,k/=i;  
  19.         }  
  20.         if(k==1)break;  
  21.     }  
  22.     if(k>1)p[++cnt]=k,c[cnt]=1;   
  23. }  
  24.   
  25. vector<int> solve()  
  26. {  
  27.     memset(ok,-1,sizeof(ok));  
  28.     vector<int>v;n--;  
  29.     for(int i=1;i<=cnt;i++)  
  30.     {  
  31.         int cm=0;  
  32.         for(int k=1;k<n;k++)  
  33.         {  
  34.             int a=n-k+1,b=k;  
  35.             while(a%p[i]==0)a/=p[i],cm++;  
  36.             while(b%p[i]==0)b/=p[i],cm--;  
  37.             if(cm<c[i])ok[k]=0;  
  38.         }  
  39.     }  
  40.     for(int i=1;i<n;i++)if(ok[i])v.push_back(i+1);  
  41.     return v;  
  42. }  
  43.   
  44. int main()  
  45. {  
  46.     while(scanf("%d%d",&n,&m)==2)  
  47.     {  
  48.         divide(m);  
  49.         ans=solve();  
  50.         printf("%d ", (int)ans.size());  
  51.         for (int i = 0; i < ans.size(); i++)   
  52.             printf("%d%c",ans[i],i==ans.size()-1?' ':' ');  
  53.         if (ans.size()==0) printf(" ");   
  54.     }  
  55.     return 0;  
  56. }  
原文地址:https://www.cnblogs.com/NSD-email0820/p/9865529.html