luogu2150(状压DP)

题目链接

https://www.luogu.org/problem/P2150

题解

写了上个题感觉这道相对还是好写得多。。但是还是很麻烦。。

同样对最大的质数排序,然后根据最大质数分段考虑。。

对 $\sqrt n$ 以内的质数三进制状压,代表该质数没选或者是被谁选中,再设一维表示当前质数是否被选,然后分类讨论转移即可。。




代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/**
*         ┏┓    ┏┓
*         ┏┛┗━━━━━━━┛┗━━━┓
*         ┃       ┃  
*         ┃   ━    ┃
*         ┃ >   < ┃
*         ┃       ┃
*         ┃... ⌒ ...  ┃
*         ┃ ┃
*         ┗━┓ ┏━┛
*          ┃ ┃ Code is far away from bug with the animal protecting          
*          ┃ ┃ 神兽保佑,代码无bug
*          ┃ ┃           
*          ┃ ┃       
*          ┃ ┃
*          ┃ ┃           
*          ┃ ┗━━━┓
*          ┃ ┣┓
*          ┃ ┏┛
*          ┗┓┓┏━━━━━━━━┳┓┏┛
*           ┃┫┫ ┃┫┫
*           ┗┻┛ ┗┻┛
*/

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<queue>
#include<map>
#include<stack>
#include<cmath>
#include<set>
#include<bitset>
#include<complex>
#include<cstdlib>
#include<assert.h>
#define inc(i,l,r) for(int i=l;i<=r;i++)
#define dec(i,l,r) for(int i=l;i>=r;i--)
#define link(x) for(edge *j=h[x];j;j=j->next)
#define mem(a) memset(a,0,sizeof(a))
#define ll long long
#define mid (x+y>>1)
#define eps 1e-8
#define succ(x) (1<<(x))
#define lowbit(x) (x&(-x))
#define sqr(x) ((x)*(x))
#define NM 505
#define nm 256
using namespace std;
const double pi=acos(-1);
ll read(){
ll x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}



const int p[]={2,3,5,7,11,13,17,19};
const int m=7;
const int tot=succ(8)-1;
ll inf;
inline void reduce(ll&x){x+=x>>63&inf;}
inline void upd(ll&x,ll y){reduce(x+=y-inf);}
int n;
int mn[NM],c[NM],_t,tmp[NM];
ll d[2][nm][nm][3],ans;
bool cmp(int x,int y){return mn[x]<mn[y];}

int main(){
n=read();inf=read();
inc(i,2,n)if(!mn[i])for(int j=i;j<=n;j+=i)mn[j]=i;
inc(i,2,n)inc(j,0,m)if(i%p[j]==0)c[i]|=succ(j);
inc(i,2,n)if(mn[i]<=19)mn[i]=0;
inc(i,2,n)tmp[i]=i;
sort(tmp+2,tmp+1+n,cmp);
d[0][0][0][0]=1;
inc(_k,2,n){
int i=tmp[_k];
_t^=1;
if(mn[i]==mn[tmp[_k-1]]){
if(mn[i]){
inc(j,0,tot)for(int k=j;;k=(k-1)&j){
inc(v,0,2)d[_t][j][k][v]=d[_t^1][j][k][v];
if(k==0)break;
}
inc(j,0,tot)for(int k=j;;k=(k-1)&j){
inc(v,0,2){
if((k&c[i])==0&&v!=2)
upd(d[_t][j|c[i]][k][1],d[_t^1][j][k][v]);
if(((k^j)&c[i])==0&&v!=1)
upd(d[_t][j|c[i]][k|c[i]][2],d[_t^1][j][k][v]);
}
if(k==0)break;
}
}else{
inc(j,0,tot)for(int k=j;;k=(k-1)&j){
d[_t][j][k][0]=d[_t^1][j][k][0];
if(k==0)break;
}
inc(j,0,tot)for(int k=j;;k=(k-1)&j){
if((k&c[i])==0)
upd(d[_t][j|c[i]][k][0],d[_t^1][j][k][0]);
if(((k^j)&c[i])==0)
upd(d[_t][j|c[i]][k|c[i]][0],d[_t^1][j][k][0]);
if(k==0)break;
}
}
}else{
inc(j,0,tot)for(int k=j;;k=(k-1)&j){
inc(v,0,2)d[_t][j][k][v]=0;
inc(v,0,2)upd(d[_t][j][k][0],d[_t^1][j][k][v]);
if(k==0)break;
}
inc(j,0,tot)for(int k=j;;k=(k-1)&j){
if((k&c[i])==0)
inc(v,0,2)
upd(d[_t][j|c[i]][k][1],d[_t^1][j][k][v]);
if(((k^j)&c[i])==0)
inc(v,0,2)
upd(d[_t][j|c[i]][k|c[i]][2],d[_t^1][j][k][v]);
if(k==0)break;
}
}
}
inc(j,0,tot)for(int k=j;;k=(k-1)&j){
inc(v,0,2)upd(ans,d[_t][j][k][v]);
if(k==0)break;
}
printf("%lld\n",ans);
return 0;
}