传送门:bzoj4197
题解
状压dp了解一下。 500−−−√ 500 以下的质数就八个,其他特殊因数用pair存。状态转移要注意。
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<iostream>
#include<algorithm>
#include<vector>
#define N (1<<8)
#define mp make_pair
#define fr first
#define sc second
using namespace std;
int n,r,p;
int y[10]={2,3,5,7,11,13,17,19};
int f[260][260],g[2][260][260],ans;
pair<int,int>q[505];
inline void mo(int& x){if(x>=p) x%=p;else if(x<0) x+=p;}//x -> &x
int main(){
scanf("%d%d",&n,&p);
for(int x,z,j,i=2;i<=n;i++){
x=i;z=0;
for(j=0;j<8 && x!=1;j++){
if(x%y[j]==0){
while(x%y[j]==0) x/=y[j];
z|=(1<<j);
}
}
q[i].fr=x;q[i].sc=z;
}
sort(q+2,q+n+1);
f[0][0]=1;
for(int i=2;i<=n;i++){
if(i==2 || q[i].fr==1 || q[i].fr != q[i-1].fr){
for(int j=0;j<N;j++)
for(int k=0;k<N;k++)
g[0][j][k]=g[1][j][k]=f[j][k];
}
for(int j=N-1;j>=0;j--){
for(int k=N-1;k>=0;k--){
if((k&q[i].sc)==0) mo(g[0][j|q[i].sc][k]+=g[0][j][k]);
if((j&q[i].sc)==0) mo(g[1][j][k|q[i].sc]+=g[1][j][k]);
}
}
if(i==n || q[i].fr==1 || q[i].fr!=q[i+1].fr){
for(int j=N-1;j>=0;j--){
for(int k=N-1;k>=0;k--){
mo(f[j][k]=g[0][j][k]+g[1][j][k]-f[j][k]);
}
}
}
}
for(int i=0;i<N;i++)
for(int j=0;j<N;j++)
if((i&j)==0) mo(ans+=f[i][j]);
//i&j==0 -> (i&j)==0
printf("%d\n",(ans%p+p)%p);
return 0;
}