题目链接: http://acm.hust.edu.cn/vjudge/problem/viewProblem.action?id=32215
经过紫书的分析,已经将问题转化为求组合数C(n-1, 0)~C(n-1, n-1)中能够被m整除的个数,并输出编号(这n个数的编号从1开始)
首先将m分解质因数,然后记录下每个质因子对应的指数。
一个没什么用的小优化:因为杨辉三角每一行都是对称的,所以我们可以求出前一半答案,然后根据对称性求出后一半的答案。
需要注意的是,如果答案中有类似C(10, 5)的数,就不要再对称了,会重复的。
这个优化貌似也只能优化0.05s左右。
代码:
#include<cstdio>
#include<iostream>
#include<cstring>
#include<string>
#include<cmath>
#include<algorithm>
using namespace std;
const int maxn=100001;
int prime[maxn],bad[maxn],e[maxn],ans[maxn];
int p_cnt;
void prime_factors(int m)
{
p_cnt=0;
for(int i=2;i<=sqrt(m);i++)
{
if(m%i==0)
prime[p_cnt++]=i;
while(m%i==0)
{
e[p_cnt-1]++;
m=m/i;
}
}
if(m>1)
{
prime[p_cnt]=m;
e[p_cnt++]=1;
}
}
int main()
{
int m,n;
while(scanf("%d%d",&n,&m)!=EOF)
{
memset(prime,0,sizeof(prime));
memset(bad,0,sizeof(bad));
memset(e,0,sizeof(e));
memset(ans,0,sizeof(ans));
n--;
prime_factors(m);
for(int i=0;i<p_cnt;i++)
{
int p=prime[i];
int need=e[i];
int cur_e=0;
for(int k=1;k<=n/2;k++)
{
int x=n-k+1;
while(x%p==0)
{
cur_e++;x/=p;
}
x=k;
while(x%p==0)
{
cur_e--;x/=p;
}
if(cur_e<need)
bad[k]=1;
}
}
int ans_cnt=0;
for(int k=1;k<=n/2;k++)
{
if(!bad[k])
ans[ans_cnt++]=k;
}
if(ans_cnt)
{
int p=ans_cnt-1;
if(ans[p]*2==n)
p--;
for(int i=p;i>=0;i--)
{
ans[ans_cnt++]=n-ans[i];
}
printf("%d\n",ans_cnt);
printf("%d",ans[0]+1);
for(int i=1;i<ans_cnt;i++)
printf(" %d",ans[i]+1);
}
else
puts("0");
printf("\n");
}
return 0;
}