题目传送门(LGOJ)&&ZOJ&&UVAlife&&POJ&&UVA&&百练
为什么我们网站的数据这么水
又有1周没有出题解了,补一补
这道题,我们粗略的推一下,发现这里面的每一项合并之后是杨辉三角形里的第行的每一个数,如图所示::
样例中的5,对应的是杨辉三角形的第五排,第五排中模3余0的只有第三个数
于是我们自然而然的想到去求杨辉三角
但我们会发现
题目给出的数据太大了
然后呢,因为这是排列组合的题
所以我们就会想到排列组合(废话)
但我们算杨辉三角不一定要递推
我们还可以用排列组合
而这里杨辉三角的第排的第个的值是
进而又想起排列组合的另一个公式::
又可以推出::
因为::
当然,这只是解题的一小部分
第100000排的杨辉三角形肯定是远远大于2147483647(INT_MAX)甚至远远大于9223372036854775807(LONGLONG_MAX)甚至有可能超过double和long double
所以投机取巧是不存在的
但是
我们有一种方法可以避免高精度运算
就是分解质因数
因为
而
最多也只有10个质因子
而求质因子又有什么用呢??
我们想一想
如果m的质因子
这个数都有
且每一种质因子的个数都比m的大
那么这个数是不是一定是m的倍数???
我们假设m的质因子分解出来是:2,2,3,3,5,11,13,13
有一个数的质因子分解出来是:2,2,2,3,3,5,11,11,11,13,13
那么这个数一定能被m整除
而且这个数除以m一定是2*11*11=242
因为其他的都怼了嘛
用计算器算一下
m=334620
这个数=80978040
所以这是一点
然后在最开始的地方用欧拉筛法筛出一个1~100000的素数表
就好了
下面是代码::
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=100000;
int p[10005],cnt;
bool h[N+5];//素数的记录
int n,m,c;
int mys[15],mgs[15],ngs[15],cmt;//mys是m(m)的因数(ys),mgs是m的因数的个数(gs),n代表当前数
void add(int a,int wh)
{
for(int i=1;i<=cmt&&a>1;i++)
{
while(a%p[mys[i]]==0)
{
ngs[i]+=wh;//是m的质因子中的才用计算
a/=p[mys[i]];
}
}
}
int main()
{
for(int i=2;i<=N;i++)
{
if(!h[i])
p[++cnt]=i;
for(int j=1;j<=cnt&&i*p[j]<=N;j++)
h[i*p[j]]=1;
}//欧拉筛法是O(n)的,很快
scanf("%d%d",&n,&m);
n--;
if(m==1){printf("0");return 0;}//任何数都是1的倍数
for(int i=1;i<=cnt&&m>1;i++)//找m的质因子
{
if(m%p[i]==0)
{
mys[++cmt]=i;//第cmt种
while(m%p[i]==0)
{
mgs[cmt]++;//个数++
m/=p[i];
}
}
}
if(m>1){printf("0");return 0;}
for(int i=1;i<=n;i++)
{
add(n-i+1,1);
add(i,-1);//计算当前数的质因子个数
int f=1;//标记
for(int j=1;j<=cmt;j++)
{
if(ngs[j]<mgs[j])//不是m的倍数,上面推过的
{
f=0;//不存在,标记
break;//终止循环
}
}
if(f==1)//是m的倍数
{
c=1;//标记,至少一个无关
printf("%d\n",i+1);
}
}
if(!c){printf("0");return 0;}//全部有关
}
当然,这不是我的代码风格
这才是我的::
#include<cstdio>
inline void read(int &x) {
x=0;
int f=1;
char s=getchar();
while(s<'0'||s>'9') {
if(s=='-')
f=-1;
s=getchar();
}
while(s>='0'&&s<='9') {
x=x*10+s-48;
s=getchar();
}
x*=f;
}
inline void pr(int x) {
if(x<0) {
putchar('-');
x=-x;
}
if(x>9)
pr(x/10);
putchar(x%10+48);
}
int p[10005],cnt,n,m,c,mys[15],mgs[15],ngs[15],cmt;
bool h[100005];
inline void add(int a,int wh) {
for(int i=1;i<=cmt&&a>1;i++)
while(a%p[mys[i]]==0) {
ngs[i]+=wh;
a/=p[mys[i]];
}
}
int main() {
for(int i=2;i<=100000;i++) {
if(h[i]==0)
p[++cnt]=i;
for(int j=1;j<=cnt&&i*p[j]<=100000;j++)
h[i*p[j]]=1;
}
read(n),read(m);
n--;
if(m==1) {
putchar(48);
return 0;
}
for(int i=1;i<=cnt&&m>1;i++)
if(m%p[i]==0) {
mys[++cmt]=i;
while(m%p[i]==0) {
mgs[cmt]++;
m/=p[i];
}
}
if(m>1) {
putchar(48);
return 0;
}
for(int i=1;i<=n;i++) {
add(n-i+1,1);
add(i,-1);
int f=1;
for(int j=1;j<=cmt;j++)
if(ngs[j]<mgs[j]) {
f=0;
break;
}
if(f==1) {
c=1;
pr(i+1),putchar('\n');
}
}
if(!c)
putchar(48);
}
思路来源于上面那个代码的码农
依然是一个同校大佬
谢谢支持!!!