简介:
对于给定的n个数a1,a2,a3,… ,an,依次求出相邻两个数的和,得到一个新数列
重复上述操作,直到最后变成一个数
问这个数除以m的余数与那些数无关
分析:
我们不妨先来看一个简单的例子:
当n=5的时候,“1 4 6 4 1”正好是杨辉三角的第4行
ai的系数就是C(n-1,i-1)
这样,问题就变成了C(n-1,i)中那些是m的倍数
我们可以通过式子:
C(n,k)=C(n,k-1)*(n-k+1)/k
在O(n)的时间内计算出所有系数
这样就解决了吗?
很可惜,因为n的范围太大,我们需要高精度才能存的下
有人愿意写高精度吗???
幸运的是,这道题只关心那些是m的倍数,
我们其实只需要计算m的唯一分解式中各素因子在C(n-1,i)中的指数即可完成判断
这些指数可以通过C(n,k)=C(n,k-1)*(n-k+1)/k 递推得到
注意:
不能直接递推每个系数除以m的余数,因为%m意义下逆元不一定存在
题目思路分析到这里就结束了,说着简单,实际上代码中有很多细节:
首先我们需要筛出素数,筛多少呢
因为m<=1e9,所以我们筛到sqrt(m)=32000即可接下来是对于m的预处理
我们需要把m分解一下
void prepare()
{
for (int i=1;i<=tot&&sshu[i]<=m;i++)
{
if (m%sshu[i]==0)
{
tt++;
yue[tt]=sshu[i];
}
while ((m%sshu[i]==0)&&(m/=sshu[i]))
mm[tt]++;
}
//在这之前都是很正常的分解
if (m!=1) //如果sqrt(m)的质数内都没有m的约数,说明剩下的部分一定是一个大质数
{
tt++; //我们需要把ta加入,不能忽略,因为这牵扯到之后是否整除的判断
yue[tt]=m;
mm[tt]=1;
}
}
- 核心部分:判断是否整除
这一部分的细节超多
看一下这句话:if (fj(n-i,i))
表示我们要在分解式上*(n-i)/i
为什么是这个数呢?
因为第i+1个数的系数是:C(n-1,i)
C(n-1,i+1)=C(n-1,i)*((n-1)-i+1)/i
(因为m最小值是2,而a1和an的系数一定是1,所以我们直接不考虑)
在分解的过程中,
为了节约时间,我们只枚举m的素因子,
我们直接在m的分解式上做文章,
如果能整除,那么C(n-1,i)的质因数的次数一定是大于m的次数
这样减完了之后,mm[k]<=0
int fj(int x,int y)
{
bool ff=1;
for (int i=1;i<=tt;i++)
{
while ((x%yue[i]==0)&&(x/=yue[i])) mm[i]--;
while ((y%yue[i]==0)&&(y/=yue[i])) mm[i]++;
if (mm[i]>0) ff=0; //一开始我写的是return 0,结果狂WA不止
//原因在于*x/y的操作一定要处理完再返回,如果中途return,就有可能使操作被跳过,影响之后的判断
}
return ff; //
}
for (int i=1;i<n;i++)
if (fj(n-i,i)) //可以整除m
{
ans[0]++;
ans[ans[0]]=i+1;
}
- 最后是出答案的时候
注意格式
//这里写代码片
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
const int N=32005;
int sshu[N],tot=0,n,m;
int ans[100010],mm[30],yue[30],tt=0;
bool no[N];
void prime()
{
memset(no,0,sizeof(no));
for (int i=2;i<N;i++)
{
if (!no[i]) sshu[++tot]=i;
for (int j=1;j<=tot&&sshu[j]*i<N;j++)
{
no[sshu[j]*i]=1;
if (i%sshu[j]==0) break;
}
}
}
int fj(int x,int y)
{
bool ff=1;
for (int i=1;i<=tt;i++)
{
while ((x%yue[i]==0)&&(x/=yue[i])) mm[i]--;
while ((y%yue[i]==0)&&(y/=yue[i])) mm[i]++;
if (mm[i]>0) ff=0; //一开始我写的是return 0,结果狂WA不止
//原因在于*x/y的操作一定要处理完再返回,如果中途return,就有可能使操作被跳过,影响之后的判断
}
return ff;
}
void prepare()
{
for (int i=1;i<=tot&&sshu[i]<=m;i++)
{
if (m%sshu[i]==0)
{
tt++;
yue[tt]=sshu[i];
}
while ((m%sshu[i]==0)&&(m/=sshu[i]))
mm[tt]++;
}
if (m!=1)
{
tt++;
yue[tt]=m;
mm[tt]=1;
}
}
int main()
{
prime();
while (scanf("%d%d",&n,&m)!=EOF)
{
memset(mm,0,sizeof(mm));
memset(yue,0,sizeof(yue));
ans[0]=0; tt=0;
prepare();
for (int i=1;i<n;i++)
if (fj(n-i,i)) //可以整除m
{
ans[0]++;
ans[ans[0]]=i+1;
}
printf("%d\n",ans[0]);
if (ans[0]!=0)
{
printf("%d",ans[1]);
for (int i=2;i<=ans[0];i++) printf(" %d",ans[i]);
}
printf("\n");
}
return 0;
}