题目链接 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先唯一分解,之后根据组合数的递推式
Ckn=n−k+1kCk−1n
C
n
k
=
n
−
k
+
1
k
C
n
k
−
1
来递推所有项,注意输出格式即使没有符合要求的项也要在第二行输出一个换行
#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;
}