/* 先求出全部的再删去没有质数的,矩阵乘法随便转移一下。 f[i][j]表示选i个,总和%p=j的方案数。 */ #include<iostream> #include<cstdio> #include<cstring> #define N 110 #define M 20000010 #define lon long long #define mod 20170408 using namespace std; int n,m,p,mark[M],prime[M],num,s1[N],s2[N]; struct node{ node(){memset(a,0,sizeof(a));} lon a[N][N]; };node jc; node operator *(node x,node y){ node z; for(int i=0;i<p;i++) for(int j=0;j<p;j++) for(int k=0;k<p;k++) z.a[i][j]=(z.a[i][j]+x.a[i][k]*y.a[k][j])%mod; //注意这里只mod一次就好,mod多了会超时! return z; } node operator ^(node x,int y){ node z; for(int i=0;i<p;i++) z.a[i][i]=1; while(y){ if(y&1) z=z*x; x=x*x; y>>=1; } return z; } void init(){ for(int i=2;i<=m;i++) mark[i]=1; for(int i=2;i<=m;i++){ if(mark[i]) prime[++num]=i; for(int j=1;j<=num&&i*prime[j]<=m;j++){ mark[i*prime[j]]=0; if(i%prime[j]==0) break; } } int mm=m/p; for(int i=1;i<=mm+1;i++) for(int j=1;j<=p&&(i-1)*p+j<=m;j++){ if(!mark[(i-1)*p+j]) s2[j]++;//!pri s1[j]++;//all } s1[0]=s1[p];s2[0]=s2[p]; } int main(){ scanf("%d%d%d",&n,&m,&p); init(); for(int i=0;i<p;i++) for(int j=0;j<p;j++) jc.a[i][j]=s1[(i-j+p)%p]; jc=jc^n; lon ans=jc.a[0][0]; for(int i=0;i<p;i++) for(int j=0;j<p;j++) jc.a[i][j]=s2[(i-j+p)%p]; jc=jc^n; cout<<((ans-jc.a[0][0])%mod+mod)%mod; return 0; }