首先考虑n<=30怎么做,没几个质因子,状压掉
然后n<=100,状压着有点费劲,各种优化,比如*2>n的质因子肯定是贡献3倍答案,*3>n的质因子可以讨论一下也不压进状态里,然后就可以卡过去了
这启发了我们正解的思路!对于大质因子我们一起转移,然后就把这个大质因子这一位扔掉。
我们只需要状压<
500−−−√
500
的那么8个质因子就好了。
然后复杂度
O(38n)
O
(
3
8
n
)
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
#define N 510
#define k1 1117
#define eps 1e-8
inline char gc(){
static char buf[1<<16],*S,*T;
if(S==T){T=(S=buf)+fread(buf,1,1<<16,stdin);if(T==S) return EOF;}
return *S++;
}
inline ll read(){
ll x=0,f=1;char ch=gc();
while(ch<'0'||ch>'9'){if(ch=='-') f=-1;ch=gc();}
while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=gc();
return x*f;
}
int n,prime[N],tot=0;
ll mod;
bool notprime[N];
inline ll mul(ll x,ll y){ll res=x*y-(ll)((long double)x/mod*y+eps)*mod;res%=mod;return res<0?res+mod:res;}
inline ll ksm(ll x,int k){
ll res=1;for(;k;k>>=1,x=mul(x,x)) if(k&1) res=mul(res,x);return res;
}
inline void getprime(){
notprime[1]=1;
for(int i=2;i<=n;++i){
if(!notprime[i]) prime[++tot]=i;
for(int j=1;prime[j]*i<=n;++j){
notprime[prime[j]*i]=1;
if(i%prime[j]==0) break;
}
}
}
namespace sol1{
bool used[N];
struct Hash_table{
ll val;int key1,key2,next;
};
inline void inc(ll &x,ll y){x+=y;x%=mod;}
struct Icefox{
Hash_table data[20000];
int h[k1][k1],num;
inline void ins(int key1,int key2,ll val){
int x=key1%k1,y=key2%k1;
for(int i=h[x][y];i;i=data[i].next)
if(data[i].key1==key1&&data[i].key2==key2){inc(data[i].val,val);return;}
data[++num].key1=key1;data[num].key2=key2;data[num].val=val;data[num].next=h[x][y];h[x][y]=num;
}inline void clear(){
for(int i=1;i<=num;++i){
int x=data[i].key1%k1,y=data[i].key2%k1;h[x][y]=0;
}num=0;
}
}f[2];
int a[N],bin[20];
inline void gao(){
bin[0]=1;int m=0,p=0;
for(int i=1;i<=tot;++i) if(prime[i]*2<=n) ++m;
for(int i=1;i<=m;++i) bin[i]=bin[i-1]<<1;
for(int i=2;i<=n;++i)
for(int j=1;j<=m;++j)
if(i%prime[j]==0) a[i]|=bin[j-1];
f[p].ins(0,0,1);
for(int j=m;j>=1;--j){
for(int x=prime[j];x<=n;x+=prime[j]){
if(used[x]) continue;used[x]=1;f[p^1].clear();
for(int i=1;i<=f[p].num;++i){
int s1=f[p].data[i].key1,s2=f[p].data[i].key2;ll val=f[p].data[i].val;
if((a[x]&s1)==0) f[p^1].ins(s1,s2|a[x],val);
if((a[x]&s2)==0) f[p^1].ins(s1|a[x],s2,val);
f[p^1].ins(s1,s2,val);
}p^=1;
}
}ll ans=0;
for(int i=1;i<=f[p].num;++i) inc(ans,f[p].data[i].val);
printf("%lld\n",mul(ans,ksm(3,tot-m)));
}
}
namespace sol2{
bool used[N],mk[N];
struct Hash_table{
ll val;int key1,key2,next;
};
inline void inc(ll &x,ll y){x+=y;x%=mod;}
struct Icefox{
Hash_table data[180000];
int h[k1][k1],num;
inline void ins(int key1,int key2,ll val){
int x=key1%k1,y=key2%k1;
for(int i=h[x][y];i;i=data[i].next)
if(data[i].key1==key1&&data[i].key2==key2){inc(data[i].val,val);return;}
data[++num].key1=key1;data[num].key2=key2;data[num].val=val;data[num].next=h[x][y];h[x][y]=num;
}inline void clear(){
for(int i=1;i<=num;++i){
int x=data[i].key1%k1,y=data[i].key2%k1;h[x][y]=0;
}num=0;
}
}f[2];
int a[N],bin[20];
inline void gao(){
bin[0]=1;int m=0,p=0,n1=0,n2=0;
for(int i=1;i<=tot;++i){
if(prime[i]*3<=n) ++m;
else if(prime[i]*2<=n) mk[prime[i]*2]=1,++n1;
else ++n2;
}
for(int i=1;i<=m;++i) bin[i]=bin[i-1]<<1;
for(int i=2;i<=n;++i)
for(int j=1;j<=m;++j)
if(i%prime[j]==0) a[i]|=bin[j-1];
f[p].ins(0,0,1);
for(int j=m;j>=1;--j){
for(int x=prime[j];x<=n;x+=prime[j]){
if(used[x]) continue;used[x]=1;f[p^1].clear();
for(int i=1;i<=f[p].num;++i){
int s1=f[p].data[i].key1,s2=f[p].data[i].key2;ll val=f[p].data[i].val;
if((a[x]&s1)==0) f[p^1].ins(s1,s2|a[x],val*(mk[x]?2:1));
if((a[x]&s2)==0) f[p^1].ins(s1|a[x],s2,val*(mk[x]?2:1));
f[p^1].ins(s1,s2,val*(mk[x]?3:1));
}p^=1;
}
}ll ans=0;
for(int i=1;i<=f[p].num;++i) inc(ans,f[p].data[i].val);
printf("%lld\n",mul(ans,ksm(3,n2)));
}
}
namespace sol3{
int a[N],bin[10];ll f[2][520][520];
bool used[N];
inline void inc(ll &x,ll y){x+=y;x%=mod;}
inline void gao(){
bin[0]=1;int m=8,p=0;
for(int i=1;i<=m+1;++i) bin[i]=bin[i-1]<<1;
for(int i=2;i<=n;++i)
for(int j=1;j<=m;++j)
if(i%prime[j]==0) a[i]|=bin[j-1];
f[p][0][0]=1;
for(int j=tot;j>8;--j){
for(int i=1;;i++){
if(prime[j]*i>n) break;int x=prime[j]*i;used[x]=1;memset(f[p^1],0,sizeof(f[p^1]));a[x]|=bin[m];
for(int s1=0;s1<bin[m+1];++s1){
int st=bin[m+1]-1-s1;
for(int s2=st;s2;s2=(s2-1)&st){
if((a[x]&s1)==0) inc(f[p^1][s1][s2|a[x]],f[p][s1][s2]);
if((a[x]&s2)==0) inc(f[p^1][s1|a[x]][s2],f[p][s1][s2]);
inc(f[p^1][s1][s2],f[p][s1][s2]);
}int s2=0;
if((a[x]&s1)==0) inc(f[p^1][s1][s2|a[x]],f[p][s1][s2]);
if((a[x]&s2)==0) inc(f[p^1][s1|a[x]][s2],f[p][s1][s2]);
inc(f[p^1][s1][s2],f[p][s1][s2]);
}p^=1;
}for(int s1=0;s1<bin[m];++s1){
int st=bin[m]-1-s1;
for(int s2=st;s2;s2=(s2-1)&st){
inc(f[p][s1][s2],f[p][s1|bin[m]][s2]),f[p][s1|bin[m]][s2]=0;
inc(f[p][s1][s2],f[p][s1][s2|bin[m]]),f[p][s1][s2|bin[m]]=0;
}int s2=0;
inc(f[p][s1][s2],f[p][s1|bin[m]][s2]),f[p][s1|bin[m]][s2]=0;
inc(f[p][s1][s2],f[p][s1][s2|bin[m]]),f[p][s1][s2|bin[m]]=0;
}
}
for(int j=1;j<=8;++j){
for(int x=prime[j];x<=n;x+=prime[j]){
if(used[x]) continue;used[x]=1;memset(f[p^1],0,sizeof(f[p^1]));
for(int s1=0;s1<bin[m];++s1){
int st=bin[m]-1-s1;
for(int s2=st;s2;s2=(s2-1)&st){
if((a[x]&s1)==0) inc(f[p^1][s1][s2|a[x]],f[p][s1][s2]);
if((a[x]&s2)==0) inc(f[p^1][s1|a[x]][s2],f[p][s1][s2]);
inc(f[p^1][s1][s2],f[p][s1][s2]);
}int s2=0;
if((a[x]&s1)==0) inc(f[p^1][s1][s2|a[x]],f[p][s1][s2]);
if((a[x]&s2)==0) inc(f[p^1][s1|a[x]][s2],f[p][s1][s2]);
inc(f[p^1][s1][s2],f[p][s1][s2]);
}p^=1;
}
}ll ans=0;
for(int s1=0;s1<bin[m];++s1){
int st=bin[m]-1-s1;
for(int s2=st;s2;s2=(s2-1)&st) inc(ans,f[p][s1][s2]);inc(ans,f[p][s1][0]);
}printf("%lld\n",ans);
}
}
int main(){
// freopen("a.in","r",stdin);
n=read();mod=read();getprime();
if(n<=50) sol1::gao();
else if(n<=100) sol2::gao();
else sol3::gao();
return 0;
}