题意:一个序列有n+1个数 最后一个为m ,前面的数都不大于m ,一个跳蚤按照这个序列使其能够跳到距离起始位置左边一个单位长度的的地方,求有多少种这种数列;
一开始读题,我 就想着 这n+1个数相加最后结果肯定是1;这需要数论的知识
如果存在x[1],x[2].....x[n],使得 data[1]*x[1]+data[2]*x[2]+......+data[3]*x[3]==1;,则,data[1],data[2],....data[n]最大公约数一定是1;
首先来证明一下:
反证法 如果存在最大公约数 d ,则data[1]*x[1]+data[2]*x[2]+......+data[3]*x[3]一定能被d 整除,所以这显然d不等于1,所以如果想让data[1]*x[1]+data[2]*x[2]+......+data[3]*x[3]==1;,data[1],data[2],....data[n]最大公约数一定是1;
一共有 m^n张卡片,如果减去其中含有公约数的卡片剩下的就是所求的结果
举个例子 n=2, m=360; 360=2^3*3^2*5
案 = (m ^ n) - (有公因数2的n元组)- (有公因数3的n元组)- (有公因数5的n元组)+ (有公因数2,3的n元组) +(有公因数2,5的n元组) + (有公因数3,5的n元组)- (有公因数2,3,5的n元组)。这个比公式形象些有公因数d的n元组,每个位置上有 (m/d)个选择(1 ~ m里面有m/d个d的倍数),根据乘法原理,可以得出有公因数d的n元组有 (m/d)^n 个。
代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
using namespace std;
__int64 sum;
__int64 num[200000],ss[200000];
__int64 m,n,per;
int l;
void totalnum(__int64 x)
{
__int64 i,j;
j=0;
memset(num,0,sizeof(num));
for(i=2;i*i<=x;i++)
{
if(x==0) break;
if(x%i==0)
{
while(x%i==0)
x/=i;
num[j]=i;
j++;
}
}
if(x!=1)
{
num[j]=x;
j++;
}
l=j;
}
__int64 powxy(__int64 x,__int64 y)
{
__int64 i;
__int64 k=1;
for(i=1;i<=y;i++)
k*=x;
return k;
}
void getx(__int64 a,__int64 b,__int64 c)//a 表示上一次录入数组的下一个数字的下标,b表示已经录入数组的数字的个数,c需要录入数组的因数的个数
{
__int64 i;
if(b==c)
{
__int64 t=m;
for(i=0;i<c;i++)
{
t=t/ss[i];
}
per+=powxy(t,n);
}
else
{
for(i=a;i<l;i++)
{
ss[b]=num[i];
getx(i+1,b+1,c);
}
}
}
int main()
{
int i;
while(scanf("%I64d%I64d",&n,&m)!=EOF)
{
totalnum(m);
sum=powxy(m,n);
for(i=0;i<l;i++)
{
per=0;
getx(0,0,i+1);
if(i%2==0)
sum-=per;
else sum+=per;
}
printf("%I64d\n",sum);
}
return 0;
}
////////////////////////////////////////////////////////////////////////////用我自己能理解的方式又写了一遍
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
#define maxnum 105
__int64 a[maxnum],b[maxnum];
__int64 n,m,sum,per;
__int64 l;
void getPrime(__int64 m)
{
__int64 i;
l=0;
memset(a,0,sizeof(a));
for(i=2;i*i<=m;i++)
{
if(m==0) break;
if(m%i==0)
{
while(m%i==0)
m/=i;
a[l]=i;
l++;
}
}
if(m>1)
{
a[l]=m;
l++;
}
}
__int64 powxy(__int64 x,__int64 y)
{
__int64 s=1;
for(int i=1;i<=y;i++)
s*=x;
return s;
}
void getResult(__int64 lastnum,__int64 endnum,__int64 neednum)
{
__int64 t,i;
if(endnum==neednum)
{
t=m;
for(i=0;i<neednum;i++)
t/=b[i];
per+=powxy(t,n);
}
else
{
for(i=lastnum;i<l;i++)
{
b[endnum]=a[i];
getResult(i+1,endnum+1,neednum);
}
}
}
int main()
{
__int64 i;
while(scanf("%I64d%I64d",&n,&m)!=EOF)
{
getPrime(m);
sum=powxy(m,n);
for(i=0;i<l;i++)
{
per=0;
getResult(0,0,i+1);
if(i%2==0)
sum-=per;
else
sum+=per;
}
printf("%I64d\n",sum);
}
return 0;
}