朴素的DP:$f[i][j]$ 表示选了 $i$ 个数,异或值为 $j$ 的方案数.
转移:$f[i][j]=\sum_{i=1}^{m}f[i-1][k]\times isprime[p]$($p$ 异或 $k$ 等于 $j$)
如果 $n$ 比较小的话可以直接进行 FWT 优化 DP.
然而,这道题中 $n=10^9$,那就用快速幂优化 DP 就好啦 ~
code:
#include <cstdio>
#include <algorithm>
#define ll long long
#define N 100002
#define MAXM 50000
#define mod 1000000007
#define setIO(s) freopen(s".in","r",stdin) // ,freopen(s".out","w",stdout)
using namespace std;
int lim,inv,tot;
int ar[N],br[N],prime[MAXM],vis[MAXM];
int qpow(int x,int y)
{
int tmp=1;
for(;y;y>>=1,x=(ll)x*x%mod)
if(y&1) tmp=(ll)tmp*x%mod;
return tmp;
}
void FWT(int *f,int opt)
{
int i,j,k;
for(i=1;i<lim;i<<=1)
{
for(j=0;j<lim;j+=i<<1)
for(k=0;k<i;++k)
{
int x=f[j+k],y=f[j+k+i];
f[j+k]=(ll)(x+y)%mod;
f[j+k+i]=(ll)(x-y+mod)%mod;
if(opt==-1)
{
f[j+k]=1ll*inv*f[j+k]%mod;
f[j+k+i]=1ll*inv*f[j+k+i]%mod;
}
}
}
}
void init()
{
int i,j;
for(i=2;i<MAXM;++i)
{
if(!vis[i]) prime[++tot]=i;
for(j=1;j<=tot&&prime[j]*i<MAXM;++j)
{
vis[i*prime[j]]=1;
if(i%prime[j]==0) break;
}
}
}
void DP(int y)
{
for(int i=0;i<lim;++i) br[i]=ar[i];
while(y)
{
if(y&1)
{
for(int i=0;i<lim;++i) ar[i]=(ll)ar[i]*br[i]%mod;
}
y>>=1;
for(int i=0;i<lim;++i)
{
br[i]=(ll)br[i]*br[i]%mod;
}
}
}
int main()
{
// setIO("input");
int i,j,n,m;
inv=qpow(2,mod-2),init();
while(scanf("%d%d",&n,&m)!=EOF)
{
for(i=1;i<=tot&&prime[i]<=m;++i) ar[prime[i]]=1;
for(lim=1;lim<=m;lim<<=1);
FWT(ar,1);
DP(n-1);
FWT(ar,-1);
printf("%d\n",ar[0]);
for(i=0;i<lim;++i) ar[i]=br[i]=0;
}
return 0;
}