题目大意:
对于给定的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;
}