题目大意:给你两个数n与m,n代表跳蚤共可以走n+1步,规定最后一步的步长为m,前n步的步长可以为1,2,......,m之中的任意一个。对于每一步步长,跳蚤可以选择向左跳或向右跳相应的长度,如果经过n+1步后,跳蚤能向左移动一步,则称该套步长集符合条件。问总共有多少套符合要求的步长集。
思路:令跳的步长为a[1],a[2],......,a[n+1],将相同长度的步长合并后,问题则转化为对于一组数串b[1],b[2],.. ... ,b[k],是否存在x[1],x[2],... ...,x[k],满足b[1]*x[1]+b[2]*x[2]+... ... +b[k]*x[k]=1,若存在,则步长满足条件。根据扩展欧几里得定理可得,若gcd(b[1],b[2],... ... ,b[k]) = 1,则符合条件。然后按照容斥定理,依次删去不符合条件的步长集,剩下的就是符合条件的。
#include <iostream>
#include <cstdio>
#include <vector>
using namespace std;
__int64 n,m,ans,sum;
vector<__int64> factor,mul_factor;
__int64 int64_pow(__int64 buttom,__int64 index)
{
__int64 res=1,i;
for (i=1;i<=index;i++)
res*=buttom;
return res;
}
void mfind(__int64 start_pos,__int64 cnt,__int64 capacity)
{
__int64 mm=m,i;
if (cnt==capacity)
{
for (i=0;i<capacity;i++)
mm/=mul_factor[i];
sum+=int64_pow(mm,n);
}
else
for (i=start_pos;i<factor.size();i++)
{
mul_factor.push_back(factor[i]);
mfind(i+1,cnt+1,capacity);
mul_factor.pop_back();
}
}
int main()
{
__int64 i,mm,sign;
while (scanf("%I64d%I64d",&n,&m)==2)
{
ans=int64_pow(m,n);
factor.clear();
mm=m;
for (i=2;i*i<=mm;i++)
if (mm%i==0)
{
while (mm%i==0)
mm/=i;
factor.push_back(i);
}
if (mm!=1)
factor.push_back(mm);
for (i=1,sign=-1;i<=factor.size();i++)
{
sum=0;
mul_factor.clear();
mfind(0,0,i);
ans+=sum*sign;
sign*=-1;
}
printf("%I64d\n",ans);
}
return 0;
}