我们很容易发现最后每一项的系数就是二项式展开,余数和m没有关系就意味着可以被m整除,因此我们就需要求出每一个二项式的系数。但是数据实在太大我们根据唯一分解定理将m和系数都进行分解,然后比较因子的幂。
二项式的计算我们可以根据杨辉三角递推,可是这个实在是太大了,递推很慢。
所以我们要知道二项式的另一个递推式:C(n,k)=C(n,k-1)*(n-k+1)/k,递推出需要的素数的分解式。
我们发现判断每一个系数是否能够被m整除需要将所有的因子进行比较,如果不处理的话109需要105 的素数表,每一次都是105的比较,这样太耗时了,很多操作都是没有意义的(因为m根本没有那么多因子)。为了优化,我们用一个表记录m的所有素因子和每个因子出现的次数,然后再用另一个数组记录系数中这些因子出现的次数,这样就可以大大提升时间效率。
输出为0的时候要多输出一个换行,需要注意。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<climits>
#include<cctype>
#include<queue>
#include<set>
#include<cmath>using namespace std;typedef long long ll;
const int INF=0x3f3f3f3f;
const int MAXN=1e5+5;
bool check[MAXN];
int prime[MAXN];
int cnt1[MAXN];
int cnt2[MAXN];
int tmp[MAXN];
int ans[MAXN];
int num,tot,top;
int n,m;void creat_prime()
{tot=0;for(int i=2;i<MAXN;i++){if(!check[i]) prime[tot++]=i;for(int j=0;j<tot && prime[j]*i<MAXN ;j++){check[prime[j]*i]=true;if(i%prime[j]==0) break;}}
}bool ok()
{for(int i=0;i<top;i++){if(cnt2[i]>tmp[i]) return false;}return true;
}void deal(int x,int d)
{for(int i=0;i<top;i++){while(x%cnt1[i]==0){tmp[i]+=d;x/=cnt1[i];}if(x==1) break;}
}int first=1;int main()
{//freopen("data.out","w",stdout);creat_prime();while(~scanf("%d%d",&n,&m)){num=0; top=0;memset(cnt2,0,sizeof(cnt2));for(int i=0;i<tot;i++){if(m%prime[i]==0){cnt1[top]=prime[i];while(m%prime[i]==0){cnt2[top]++;m/=prime[i];}top++;}if(m==1) break;}if(m!=1){cnt1[top]=m;cnt2[top]++;top++;}memset(tmp,0,sizeof(tmp));for(int i=1;i<n-1;i++){deal(n-i,1);deal(i,-1);if(ok()){ans[num++]=i+1;}}
// if(first) first=0;
// else printf("\n");printf("%d\n",num);if(num==0){printf("\n");continue;}for(int i=0;i<num-1;i++){printf("%d ",ans[i]);}printf("%d\n",ans[num-1]);}return 0;
}