标签:
看到题,就想到要利用质因子分解进行状压dp,但是质因子太多了,不能直接搞,于是考虑按最大质因子<sqrt(n)和>sqrt(n)分别讨论。对于最大质因子>sqrt(n)的每个数,只有一个质因子>sqrt(n),而<sqrt(n)的质因子是可以状压的。#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<vector>
#define ll long long
#define inf 1e9
#define eps 1e-8
using namespace std;
int f[270][270],g[2][270][270];
bool mark[510];
int S[510],P[510],ss[510],t[270],q[510];
vector<int> vec[510];
int md,m;
const int mxs=256,sq=20;
inline void add(int &a,int b)
{
a+=b; if (a>=md) a-=md;
}
void solve()
{
//printf(":: %d %d %d\n",m,q[1],q[2]);
for (int s1=0;s1<mxs;s1++)
for (int s2=0;s2<mxs;s2++)
g[0][s1][s2]=g[1][s1][s2]=f[s1][s2];
for (int i=1;i<=m;i++)
{
int x=q[i];
for (int s1=mxs-1;s1>=0;s1--)
for (int s2=mxs-1;s2>=0;s2--)
{
if ((x&s2)==0) add(g[0][s1|x][s2],g[0][s1][s2]);
if ((x&s1)==0) add(g[1][s1][s2|x],g[1][s1][s2]);
}
}
for (int s1=0;s1<mxs;s1++)
for (int s2=0;s2<mxs;s2++)
{
f[s1][s2]=g[0][s1][s2]+g[1][s1][s2]-f[s1][s2];
if (f[s1][s2]>=md) f[s1][s2]-=md;
if (f[s1][s2]<0) f[s1][s2]+=md;
}/*
for (int s1=0;s1<4;s1++){
for (int s2=0;s2<4;s2++)
printf("%d ",f[s1][s2]);
printf("\n");}*/
}
int main()
{
int n,w=0;
scanf("%d%d",&n,&md);
for (int i=2;i<=n;i++)
{
if (!mark[i])
{
ss[++w]=i;
S[i]= i>sq?0:(1<<(w-1));
P[i]=i;
}
for (int j=1;ss[j]*i<=n;j++)
{
int p=ss[j],x=i*p;
mark[x]=1; S[x]=S[i]|S[p]; P[x]=P[i];
if (i%p==0) break;
}
}
for (int i=2;i<=sq;i++) mark[i]=1;
t[0]=1;
for (int i=2;i<=n;i++)
if (P[i]<=sq)
{
vec[1].push_back(S[i]);
for (int j=mxs-1;j>=0;j--) add(t[j|S[i]],t[j]);
}
else vec[P[i]].push_back(S[i]);
//for (int i=2;i<=3;i++) printf("%d %d %d\n",mark[i],P[i],S[i]); printf("\n");
f[0][0]=1;
for (int i=1;i<=n;i++)
if (!mark[i])
{
if (i==1)
{
for (int j=vec[i].size()-1;j>=0;j--)
{
m=1; q[1]=vec[i][j]; solve();
}
}
else
{
m=0;
for (int j=vec[i].size()-1;j>=0;j--) q[++m]=vec[i][j];
solve();
}
}
int ans=0;
for (int s1=0;s1<mxs;s1++)
for (int s2=0;s2<mxs;s2++)
add(ans,f[s1][s2]);
printf("%d\n",ans);
return 0;
}
标签:
原文地址:http://blog.csdn.net/heheda_is_an_oier/article/details/51366118